diff --git a/.github/workflows/build-alpine-linux.yml b/.github/workflows/build-alpine-linux.yml index 0d366a4bdd0..a39b342a248 100644 --- a/.github/workflows/build-alpine-linux.yml +++ b/.github/workflows/build-alpine-linux.yml @@ -59,7 +59,7 @@ on: jobs: build-linux: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 container: image: alpine:3.20 diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index b3c63f488a0..e70937f57b6 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -48,7 +48,7 @@ on: jobs: build-cross-compile: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index f398625cb2c..0680dea6bbe 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -75,7 +75,7 @@ on: jobs: build-linux: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false @@ -115,9 +115,21 @@ jobs: if [[ '${{ inputs.apt-architecture }}' != '' ]]; then sudo dpkg --add-architecture ${{ inputs.apt-architecture }} fi - sudo apt-get update - sudo apt-get install --only-upgrade apt - sudo apt-get install gcc-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} g++-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} libxrandr-dev${{ steps.arch.outputs.suffix }} libxtst-dev${{ steps.arch.outputs.suffix }} libcups2-dev${{ steps.arch.outputs.suffix }} libasound2-dev${{ steps.arch.outputs.suffix }} ${{ inputs.apt-extra-packages }} + sudo apt update + sudo apt install --only-upgrade apt + sudo apt install \ + gcc-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} \ + g++-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} \ + libasound2-dev${{ steps.arch.outputs.suffix }} \ + libcups2-dev${{ steps.arch.outputs.suffix }} \ + libfontconfig1-dev${{ steps.arch.outputs.suffix }} \ + libx11-dev${{ steps.arch.outputs.suffix }} \ + libxext-dev${{ steps.arch.outputs.suffix }} \ + libxrandr-dev${{ steps.arch.outputs.suffix }} \ + libxrender-dev${{ steps.arch.outputs.suffix }} \ + libxt-dev${{ steps.arch.outputs.suffix }} \ + libxtst-dev${{ steps.arch.outputs.suffix }} \ + ${{ inputs.apt-extra-packages }} sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${{ inputs.gcc-major-version }} 100 --slave /usr/bin/g++ g++ /usr/bin/g++-${{ inputs.gcc-major-version }} - name: 'Configure' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4d1e8a8be3d..09e6ed65a47 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,7 +57,7 @@ jobs: prepare: name: 'Prepare the run' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 env: # List of platforms to exclude by default EXCLUDED_PLATFORMS: 'alpine-linux-x64' @@ -405,7 +405,7 @@ jobs: with: platform: linux-x64 bootjdk-platform: linux-x64 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} debug-suffix: -debug @@ -419,7 +419,7 @@ jobs: with: platform: linux-x64 bootjdk-platform: linux-x64 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} static-suffix: "-static" diff --git a/.gitignore b/.gitignore index 852b692f99b..0743489f8ec 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,8 @@ NashornProfile.txt *.rej *.orig test/benchmarks/**/target +/src/hotspot/CMakeLists.txt +/src/hotspot/compile_commands.json +/src/hotspot/cmake-build-debug/ +/src/hotspot/.cache/ +/src/hotspot/.idea/ diff --git a/.jcheck/conf b/.jcheck/conf index 60881e74d2a..25af49f8ef8 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1,7 +1,7 @@ [general] project=jdk jbs=JDK -version=26 +version=27 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists,copyright diff --git a/bin/generate-symbol-data.sh b/bin/generate-symbol-data.sh index 283757a6918..14d8763ad81 100644 --- a/bin/generate-symbol-data.sh +++ b/bin/generate-symbol-data.sh @@ -38,7 +38,7 @@ # directory. # - open a terminal program and run these commands: # cd "${JDK_CHECKOUT}"/src/jdk.compiler/share/data/symbols -# bash ../../../../../make/scripts/generate-symbol-data.sh "${JDK_N_INSTALL}" +# bash ../../../../../bin/generate-symbol-data.sh "${JDK_N_INSTALL}" # - this command will generate or update data for "--release N" into the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols # directory, updating all registration necessary. If the goal was to update the data, and there are no # new or changed files in the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols directory after running this script, diff --git a/doc/building.html b/doc/building.html index 99eb3e0c473..8e5a7625371 100644 --- a/doc/building.html +++ b/doc/building.html @@ -541,6 +541,11 @@ href="#apple-xcode">Apple Xcode on some strategies to deal with this.

It is recommended that you use at least macOS 14 and Xcode 15.4, but earlier versions may also work.

+

Starting with Xcode 26, introduced in macOS 26, the Metal toolchain +no longer comes bundled with Xcode, so it needs to be installed +separately. This can either be done via the Xcode's Settings/Components +UI, or in the command line calling +xcodebuild -downloadComponent metalToolchain.

The standard macOS environment contains the basic tooling needed to build, but for external libraries a package manager is recommended. The JDK uses homebrew in the examples, but @@ -668,7 +673,7 @@ update.

(Note that this version is often presented as "MSVC 14.28", and reported by cl.exe as 19.28.) Older versions will not be accepted by configure and will not work. The maximum accepted version -of Visual Studio is 2022.

+of Visual Studio is 2026.

If you have multiple versions of Visual Studio installed, configure will by default pick the latest. You can request a specific version to be used by setting diff --git a/doc/building.md b/doc/building.md index 047255d1848..b626027f101 100644 --- a/doc/building.md +++ b/doc/building.md @@ -352,6 +352,11 @@ on some strategies to deal with this. It is recommended that you use at least macOS 14 and Xcode 15.4, but earlier versions may also work. +Starting with Xcode 26, introduced in macOS 26, the Metal toolchain no longer +comes bundled with Xcode, so it needs to be installed separately. This can +either be done via the Xcode's Settings/Components UI, or in the command line +calling `xcodebuild -downloadComponent metalToolchain`. + The standard macOS environment contains the basic tooling needed to build, but for external libraries a package manager is recommended. The JDK uses [homebrew](https://brew.sh/) in the examples, but feel free to use whatever @@ -468,7 +473,7 @@ available for this update. The minimum accepted version is Visual Studio 2019 version 16.8. (Note that this version is often presented as "MSVC 14.28", and reported by cl.exe as 19.28.) Older versions will not be accepted by `configure` and will not work. -The maximum accepted version of Visual Studio is 2022. +The maximum accepted version of Visual Studio is 2026. If you have multiple versions of Visual Studio installed, `configure` will by default pick the latest. You can request a specific version to be used by diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index a2ffb57e5a3..362245cd00a 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -1037,8 +1037,8 @@ running destructors at exit can lead to problems.

Some of the approaches used in HotSpot to avoid dynamic initialization include:

+ *

When used with a {@code PEMEncoder} instance configured for encryption: + *

    + *
  • {@link PrivateKey} : ENCRYPTED PRIVATE KEY
  • + *
  • {@link KeyPair} : ENCRYPTED PRIVATE KEY
  • + *
  • {@link PKCS8EncodedKeySpec} : ENCRYPTED PRIVATE KEY
  • + *
* *

This class is immutable and thread-safe. * - *

Here is an example of encoding a {@code PrivateKey} object: + *

Example: encode a private key: * {@snippet lang = java: * PEMEncoder pe = PEMEncoder.of(); * byte[] pemData = pe.encode(privKey); * } * - *

Here is an example that encrypts and encodes a private key using the - * specified password: + *

Example: encrypt and encode a private key using a password: * {@snippet lang = java: * PEMEncoder pe = PEMEncoder.of().withEncryption(password); * byte[] pemData = pe.encode(privKey); * } * - * @implNote An implementation may support other PEM types and - * {@code DEREncodable} objects. + * @implNote Implementations may support additional PEM types. * * * @see PEMDecoder - * @see PEMRecord + * @see PEM * @see EncryptedPrivateKeyInfo * * @spec https://www.rfc-editor.org/info/rfc1421 * RFC 1421: Privacy Enhancement for Internet Electronic Mail + * @spec https://www.rfc-editor.org/info/rfc5958 + * RFC 5958: Asymmetric Key Packages * @spec https://www.rfc-editor.org/info/rfc7468 * RFC 7468: Textual Encodings of PKIX, PKCS, and CMS Structures * @@ -128,24 +127,26 @@ public final class PEMEncoder { // Singleton instance of PEMEncoder private static final PEMEncoder PEM_ENCODER = new PEMEncoder(null); - - // Stores the password for an encrypted encoder that isn't setup yet. - private PBEKeySpec keySpec; - // Stores the key after the encoder is ready to encrypt. The prevents - // repeated SecretKeyFactory calls if the encoder is used on multiple keys. - private SecretKey key; - // Makes SecretKeyFactory generation thread-safe. - private final ReentrantLock lock; + // PBE key for encryption + private final Key key; /** - * Instantiate a {@code PEMEncoder} for Encrypted Private Keys. - * - * @param pbe contains the password spec used for encryption. + * Create an encrypted {@code PEMEncoder} instance. */ - private PEMEncoder(PBEKeySpec pbe) { - keySpec = pbe; - key = null; - lock = new ReentrantLock(); + private PEMEncoder(PBEKeySpec keySpec) { + if (keySpec != null) { + try { + key = SecretKeyFactory.getInstance(Pem.DEFAULT_ALGO). + generateSecret(keySpec); + } catch (GeneralSecurityException e) { + throw new IllegalArgumentException("Operation failed: " + + "unable to generate key or locate a valid algorithm. " + + "Check the jdk.epkcs8.defaultAlgorithm security " + + "property for a valid configuration.", e); + } + } else { + key = null; + } } /** @@ -158,70 +159,90 @@ public final class PEMEncoder { } /** - * Encodes the specified {@code DEREncodable} and returns a PEM encoded + * Encodes the specified {@code DEREncodable} and returns a PEM-encoded * string. * * @param de the {@code DEREncodable} to be encoded - * @return a {@code String} containing the PEM encoded data - * @throws IllegalArgumentException if the {@code DEREncodable} cannot be - * encoded + * @return a {@code String} containing the PEM-encoded data + * @throws IllegalArgumentException if the {@code DEREncodable} cannot be encoded * @throws NullPointerException if {@code de} is {@code null} * @see #withEncryption(char[]) */ public String encodeToString(DEREncodable de) { Objects.requireNonNull(de); return switch (de) { - case PublicKey pu -> buildKey(null, pu.getEncoded()); - case PrivateKey pr -> buildKey(pr.getEncoded(), null); - case KeyPair kp -> { - if (kp.getPublic() == null) { - throw new IllegalArgumentException("KeyPair does not " + - "contain PublicKey."); - } - if (kp.getPrivate() == null) { - throw new IllegalArgumentException("KeyPair does not " + - "contain PrivateKey."); - } - yield buildKey(kp.getPrivate().getEncoded(), - kp.getPublic().getEncoded()); - } - case X509EncodedKeySpec x -> - buildKey(null, x.getEncoded()); - case PKCS8EncodedKeySpec p -> - buildKey(p.getEncoded(), null); - case EncryptedPrivateKeyInfo epki -> { + case PublicKey pu -> buildKey(pu.getEncoded(), null); + case PrivateKey pr -> { + byte[] encoding = pr.getEncoded(); try { - yield Pem.pemEncoded(Pem.ENCRYPTED_PRIVATE_KEY, - epki.getEncoded()); + yield buildKey(null, encoding); + } finally { + KeyUtil.clear(encoding); + } + } + case KeyPair kp -> { + byte[] encoding = null; + try { + if (kp.getPublic() == null) { + throw new IllegalArgumentException("KeyPair does not " + + "contain PublicKey."); + } + if (kp.getPrivate() == null) { + throw new IllegalArgumentException("KeyPair does not " + + "contain PrivateKey."); + } + encoding = kp.getPrivate().getEncoded(); + if (encoding == null || encoding.length == 0) { + throw new IllegalArgumentException("PrivateKey is " + + "null or has no encoding."); + } + yield buildKey(kp.getPublic().getEncoded(), encoding); + } finally { + KeyUtil.clear(encoding); + } + } + case X509EncodedKeySpec x -> buildKey(x.getEncoded(), null); + case PKCS8EncodedKeySpec p -> buildKey(null, p.getEncoded()); + case EncryptedPrivateKeyInfo epki -> { + byte[] encoding = null; + if (key != null) { + throw new IllegalArgumentException( + "EncryptedPrivateKeyInfo cannot be encrypted"); + } + try { + encoding = epki.getEncoded(); + yield Pem.pemEncoded(Pem.ENCRYPTED_PRIVATE_KEY, encoding); } catch (IOException e) { throw new IllegalArgumentException(e); + } finally { + KeyUtil.clear(encoding); } } case X509Certificate c -> { + if (key != null) { + throw new IllegalArgumentException("Certificates " + + "cannot be encrypted"); + } try { - if (isEncrypted()) { - throw new IllegalArgumentException("Certificates " + - "cannot be encrypted"); - } yield Pem.pemEncoded(Pem.CERTIFICATE, c.getEncoded()); } catch (CertificateEncodingException e) { throw new IllegalArgumentException(e); } } case X509CRL crl -> { + if (key != null) { + throw new IllegalArgumentException("CRLs cannot be " + + "encrypted"); + } try { - if (isEncrypted()) { - throw new IllegalArgumentException("CRLs cannot be " + - "encrypted"); - } yield Pem.pemEncoded(Pem.X509_CRL, crl.getEncoded()); } catch (CRLException e) { throw new IllegalArgumentException(e); } } - case PEMRecord rec -> { - if (isEncrypted()) { - throw new IllegalArgumentException("PEMRecord cannot be " + + case PEM rec -> { + if (key != null) { + throw new IllegalArgumentException("PEM cannot be " + "encrypted"); } yield Pem.pemEncoded(rec); @@ -233,13 +254,12 @@ public final class PEMEncoder { } /** - * Encodes the specified {@code DEREncodable} and returns the PEM encoding - * in a byte array. + * Encodes the specified {@code DEREncodable} and returns a PEM-encoded + * byte array. * * @param de the {@code DEREncodable} to be encoded - * @return a PEM encoded byte array - * @throws IllegalArgumentException if the {@code DEREncodable} cannot be - * encoded + * @return a PEM-encoded byte array + * @throws IllegalArgumentException if the {@code DEREncodable} cannot be encoded * @throws NullPointerException if {@code de} is {@code null} * @see #withEncryption(char[]) */ @@ -248,136 +268,95 @@ public final class PEMEncoder { } /** - * Returns a new {@code PEMEncoder} instance configured for encryption - * with the default algorithm and a given password. + * Returns a copy of this PEMEncoder that encrypts and encodes + * using the specified password and default encryption algorithm. * - *

Only {@link PrivateKey} objects can be encrypted with this newly - * configured instance. Encoding other {@link DEREncodable} objects will + *

Only {@code PrivateKey}, {@code KeyPair}, and + * {@code PKCS8EncodedKeySpec} objects can be encoded with this newly + * configured instance. Encoding other {@code DEREncodable} objects will * throw an {@code IllegalArgumentException}. * - * @implNote - * The default password-based encryption algorithm is defined - * by the {@code jdk.epkcs8.defaultAlgorithm} security property and - * uses the default encryption parameters of the provider that is selected. - * For greater flexibility with encryption options and parameters, use - * {@link EncryptedPrivateKeyInfo#encryptKey(PrivateKey, Key, + * @implNote The {@code jdk.epkcs8.defaultAlgorithm} security property + * defines the default encryption algorithm. The {@code AlgorithmParameterSpec} + * defaults are determined by the provider. To use non-default encryption + * parameters, or to encrypt with a different encryption provider, use + * {@link EncryptedPrivateKeyInfo#encrypt(DEREncodable, Key, * String, AlgorithmParameterSpec, Provider, SecureRandom)} and use the * returned object with {@link #encode(DEREncodable)}. * * @param password the encryption password. The array is cloned and - * stored in the new instance. + * stored in the new instance. * @return a new {@code PEMEncoder} instance configured for encryption - * @throws NullPointerException when password is {@code null} + * @throws NullPointerException if password is {@code null} + * @throws IllegalArgumentException if generating the encryption key fails */ public PEMEncoder withEncryption(char[] password) { - // PBEKeySpec clones the password Objects.requireNonNull(password, "password cannot be null."); - return new PEMEncoder(new PBEKeySpec(password)); + PBEKeySpec keySpec = new PBEKeySpec(password); + try { + return new PEMEncoder(keySpec); + } finally { + keySpec.clearPassword(); + } } /** * Build PEM encoding. + * + * privateKeyEncoding will be zeroed when the method returns */ - private String buildKey(byte[] privateBytes, byte[] publicBytes) { - DerOutputStream out = new DerOutputStream(); - Cipher cipher; - - if (privateBytes == null && publicBytes == null) { + private String buildKey(byte[] publicEncoding, byte[] privateEncoding) { + if (publicEncoding == null && privateEncoding == null) { throw new IllegalArgumentException("No encoded data given by the " + "DEREncodable."); } - // If `keySpec` is non-null, then `key` hasn't been established. - // Setting a `key` prevents repeated key generation operations. - // withEncryption() is a configuration method and cannot throw an - // exception; therefore generation is delayed. - if (keySpec != null) { - // For thread safety - lock.lock(); - if (key == null) { - try { - key = SecretKeyFactory.getInstance(Pem.DEFAULT_ALGO). - generateSecret(keySpec); - keySpec.clearPassword(); - keySpec = null; - } catch (GeneralSecurityException e) { - throw new IllegalArgumentException("Security property " + - "\"jdk.epkcs8.defaultAlgorithm\" may not specify a " + - "valid algorithm. Operation cannot be performed.", e); - } finally { - lock.unlock(); - } - } else { - lock.unlock(); - } + if (publicEncoding != null && publicEncoding.length == 0) { + throw new IllegalArgumentException("Public key has no " + + "encoding"); } - // If `key` is non-null, this is an encoder ready to encrypt. - if (key != null) { - if (privateBytes == null || publicBytes != null) { - throw new IllegalArgumentException("Can only encrypt a " + - "PrivateKey."); - } + if (privateEncoding != null && privateEncoding.length == 0) { + throw new IllegalArgumentException("Private key has no " + + "encoding"); + } - try { - cipher = Cipher.getInstance(Pem.DEFAULT_ALGO); - cipher.init(Cipher.ENCRYPT_MODE, key); - } catch (GeneralSecurityException e) { - throw new IllegalArgumentException("Security property " + - "\"jdk.epkcs8.defaultAlgorithm\" may not specify a " + - "valid algorithm. Operation cannot be performed.", e); - } - - try { - new AlgorithmId(Pem.getPBEID(Pem.DEFAULT_ALGO), - cipher.getParameters()).encode(out); - out.putOctetString(cipher.doFinal(privateBytes)); - return Pem.pemEncoded(Pem.ENCRYPTED_PRIVATE_KEY, - DerValue.wrap(DerValue.tag_Sequence, out).toByteArray()); - } catch (GeneralSecurityException e) { - throw new IllegalArgumentException(e); - } + if (key != null && privateEncoding == null) { + throw new IllegalArgumentException("This DEREncodable cannot " + + "be encrypted."); } // X509 only - if (publicBytes != null && privateBytes == null) { - if (publicBytes.length == 0) { - throw new IllegalArgumentException("No public key encoding " + - "given by the DEREncodable."); - } - - return Pem.pemEncoded(Pem.PUBLIC_KEY, publicBytes); + if (publicEncoding != null && privateEncoding == null) { + return Pem.pemEncoded(Pem.PUBLIC_KEY, publicEncoding); } - // PKCS8 only - if (publicBytes == null && privateBytes != null) { - if (privateBytes.length == 0) { + byte[] encoding = null; + PKCS8EncodedKeySpec p8KeySpec = null; + try { + if (publicEncoding == null) { + encoding = privateEncoding; + } else { + encoding = PKCS8Key.getEncoded(publicEncoding, + privateEncoding); + } + if (key != null) { + p8KeySpec = new PKCS8EncodedKeySpec(encoding); + encoding = EncryptedPrivateKeyInfo.encrypt(p8KeySpec, key, + Pem.DEFAULT_ALGO, null, null, null). + getEncoded(); + } + if (encoding.length == 0) { throw new IllegalArgumentException("No private key encoding " + "given by the DEREncodable."); } - - return Pem.pemEncoded(Pem.PRIVATE_KEY, privateBytes); - } - - // OneAsymmetricKey - if (privateBytes.length == 0) { - throw new IllegalArgumentException("No private key encoding " + - "given by the DEREncodable."); - } - - if (publicBytes.length == 0) { - throw new IllegalArgumentException("No public key encoding " + - "given by the DEREncodable."); - } - try { - return Pem.pemEncoded(Pem.PRIVATE_KEY, - PKCS8Key.getEncoded(publicBytes, privateBytes)); + return Pem.pemEncoded( + (key == null ? Pem.PRIVATE_KEY : Pem.ENCRYPTED_PRIVATE_KEY), + encoding); } catch (IOException e) { - throw new IllegalArgumentException(e); + throw new IllegalArgumentException("Error while encoding", e); + } finally { + KeyUtil.clear(encoding, p8KeySpec); } } - - private boolean isEncrypted() { - return (key != null || keySpec != null); - } } diff --git a/src/java.base/share/classes/java/security/PEMRecord.java b/src/java.base/share/classes/java/security/PEMRecord.java deleted file mode 100644 index 2ce567f9fde..00000000000 --- a/src/java.base/share/classes/java/security/PEMRecord.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.security; - -import jdk.internal.javac.PreviewFeature; - -import sun.security.util.Pem; - -import java.util.Objects; - -/** - * {@code PEMRecord} is a {@link DEREncodable} that represents Privacy-Enhanced - * Mail (PEM) data by its type and Base64 form. {@link PEMDecoder} and - * {@link PEMEncoder} use {@code PEMRecord} when representing the data as a - * cryptographic object is not desired or the type has no - * {@code DEREncodable}. - * - *

{@code type} and {@code content} may not be {@code null}. - * {@code leadingData} may be null if no non-PEM data preceded PEM header - * during decoding. {@code leadingData} may be useful for reading metadata - * that accompanies PEM data. - * - *

No validation is performed during instantiation to ensure that - * {@code type} conforms to {@code RFC 7468}, that {@code content} is valid - * Base64, or that {@code content} matches the {@code type}. - * {@code leadingData} is not defensively copied and does not return a - * clone when {@linkplain #leadingData()} is called. - * - * @param type the type identifier in the PEM header without PEM syntax labels. - * For a public key, {@code type} would be "PUBLIC KEY". - * @param content the Base64-encoded data, excluding the PEM header and footer - * @param leadingData any non-PEM data preceding the PEM header when decoding. - * - * @spec https://www.rfc-editor.org/info/rfc7468 - * RFC 7468: Textual Encodings of PKIX, PKCS, and CMS Structures - * - * @see PEMDecoder - * @see PEMEncoder - * - * @since 25 - */ -@PreviewFeature(feature = PreviewFeature.Feature.PEM_API) -public record PEMRecord(String type, String content, byte[] leadingData) - implements DEREncodable { - - /** - * Creates a {@code PEMRecord} instance with the given parameters. - * - * @param type the type identifier - * @param content the Base64-encoded data, excluding the PEM header and - * footer - * @param leadingData any non-PEM data read during the decoding process - * before the PEM header. This value maybe {@code null}. - * @throws IllegalArgumentException if {@code type} is incorrectly - * formatted. - * @throws NullPointerException if {@code type} and/or {@code content} are - * {@code null}. - */ - public PEMRecord { - Objects.requireNonNull(type, "\"type\" cannot be null."); - Objects.requireNonNull(content, "\"content\" cannot be null."); - - // With no validity checking on `type`, the constructor accept anything - // including lowercase. The onus is on the caller. - if (type.startsWith("-") || type.startsWith("BEGIN ") || - type.startsWith("END ")) { - throw new IllegalArgumentException("PEM syntax labels found. " + - "Only the PEM type identifier is allowed"); - } - - } - - /** - * Creates a {@code PEMRecord} instance with a given {@code type} and - * {@code content} data in String form. {@code leadingData} is set to null. - * - * @param type the PEM type identifier - * @param content the Base64-encoded data, excluding the PEM header and - * footer - * @throws IllegalArgumentException if {@code type} is incorrectly - * formatted. - * @throws NullPointerException if {@code type} and/or {@code content} are - * {@code null}. - */ - public PEMRecord(String type, String content) { - this(type, content, null); - } - - /** - * Returns the type and Base64 encoding in PEM format. {@code leadingData} - * is not returned by this method. - */ - @Override - public String toString() { - return Pem.pemEncoded(this); - } -} diff --git a/src/java.base/share/classes/java/text/CollationElementIterator.java b/src/java.base/share/classes/java/text/CollationElementIterator.java index 5469b95b11e..46fe80e1bda 100644 --- a/src/java.base/share/classes/java/text/CollationElementIterator.java +++ b/src/java.base/share/classes/java/text/CollationElementIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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 @@ -661,7 +661,7 @@ public final class CollationElementIterator // (the Normalizer is cloned here so that the seeking we do in the next loop // won't affect our real position in the text) - NormalizerBase tempText = (NormalizerBase)text.clone(); + NormalizerBase tempText = text.clone(); // extract the next maxLength characters in the string (we have to do this using the // Normalizer to ensure that our offsets correspond to those the rest of the @@ -732,7 +732,7 @@ public final class CollationElementIterator pair = list.lastElement(); int maxLength = pair.entryName.length(); - NormalizerBase tempText = (NormalizerBase)text.clone(); + NormalizerBase tempText = text.clone(); tempText.next(); key.setLength(0); diff --git a/src/java.base/share/classes/java/time/LocalDate.java b/src/java.base/share/classes/java/time/LocalDate.java index 016bdab5394..2105621d135 100644 --- a/src/java.base/share/classes/java/time/LocalDate.java +++ b/src/java.base/share/classes/java/time/LocalDate.java @@ -79,6 +79,8 @@ import java.io.DataOutput; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; +import java.io.ObjectStreamField; +import java.io.Serial; import java.io.Serializable; import java.time.chrono.ChronoLocalDate; import java.time.chrono.IsoEra; @@ -142,6 +144,22 @@ import jdk.internal.util.DateTimeHelper; public final class LocalDate implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable { + /** + * For backward compatibility of the serialized {@code LocalDate.class} object, + * explicitly declare the types of the serialized fields as defined in Java SE 8. + * Instances of {@code LocalDate} are serialized using the dedicated + * serialized form by {@code writeReplace}. + * @serialField year int The year. + * @serialField month short The month-of-year. + * @serialField day short The day-of-month. + */ + @Serial + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("year", int.class), + new ObjectStreamField("month", short.class), + new ObjectStreamField("day", short.class) + }; + /** * The minimum supported {@code LocalDate}, '-999999999-01-01'. * This could be used by an application as a "far past" date. @@ -178,15 +196,15 @@ public final class LocalDate /** * @serial The year. */ - private final int year; + private final transient int year; /** * @serial The month-of-year. */ - private final short month; + private final transient byte month; /** * @serial The day-of-month. */ - private final short day; + private final transient byte day; //----------------------------------------------------------------------- /** @@ -490,8 +508,8 @@ public final class LocalDate */ private LocalDate(int year, int month, int dayOfMonth) { this.year = year; - this.month = (short) month; - this.day = (short) dayOfMonth; + this.month = (byte) month; + this.day = (byte) dayOfMonth; } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/MonthDay.java b/src/java.base/share/classes/java/time/MonthDay.java index 1de4fa84d3e..26ca69bbe0d 100644 --- a/src/java.base/share/classes/java/time/MonthDay.java +++ b/src/java.base/share/classes/java/time/MonthDay.java @@ -69,6 +69,8 @@ import java.io.DataOutput; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; +import java.io.ObjectStreamField; +import java.io.Serial; import java.io.Serializable; import java.time.chrono.Chronology; import java.time.chrono.IsoChronology; @@ -86,6 +88,8 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Objects; +import jdk.internal.util.DecimalDigits; + /** * A month-day in the ISO-8601 calendar system, such as {@code --12-03}. *

@@ -133,6 +137,20 @@ public final class MonthDay */ @java.io.Serial private static final long serialVersionUID = -939150713474957432L; + + /** + * For backward compatibility of the serialized {@code MonthDay.class} object, + * explicitly declare the types of the serialized fields as defined in Java SE 8. + * Instances of {@code MonthDay} are serialized using the dedicated + * serialized form by {@code writeReplace}. + * @serialField month int The month-of-year. + * @serialField day int The day-of-month. + */ + @Serial + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("month", int.class), + new ObjectStreamField("day", int.class) + }; /** * Parser. */ @@ -144,13 +162,13 @@ public final class MonthDay .toFormatter(); /** - * @serial The month-of-year, not null. + * @serial The month-of-year. */ - private final int month; + private final transient byte month; /** * @serial The day-of-month. */ - private final int day; + private final transient byte day; //----------------------------------------------------------------------- /** @@ -319,8 +337,8 @@ public final class MonthDay * @param dayOfMonth the day-of-month to represent, validated from 1 to 29-31 */ private MonthDay(int month, int dayOfMonth) { - this.month = month; - this.day = dayOfMonth; + this.month = (byte) month; + this.day = (byte) dayOfMonth; } //----------------------------------------------------------------------- @@ -748,10 +766,12 @@ public final class MonthDay */ @Override public String toString() { - return new StringBuilder(10).append("--") - .append(month < 10 ? "0" : "").append(month) - .append(day < 10 ? "-0" : "-").append(day) - .toString(); + StringBuilder buf = new StringBuilder(10); + buf.append("--"); + DecimalDigits.appendPair(buf, month); + buf.append('-'); + DecimalDigits.appendPair(buf, day); + return buf.toString(); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/YearMonth.java b/src/java.base/share/classes/java/time/YearMonth.java index 8ad1172811f..665c8c85544 100644 --- a/src/java.base/share/classes/java/time/YearMonth.java +++ b/src/java.base/share/classes/java/time/YearMonth.java @@ -78,6 +78,8 @@ import java.io.DataOutput; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; +import java.io.ObjectStreamField; +import java.io.Serial; import java.io.Serializable; import java.time.chrono.Chronology; import java.time.chrono.IsoChronology; @@ -99,6 +101,8 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Objects; +import jdk.internal.util.DecimalDigits; + /** * A year-month in the ISO-8601 calendar system, such as {@code 2007-12}. *

@@ -137,6 +141,20 @@ public final class YearMonth */ @java.io.Serial private static final long serialVersionUID = 4183400860270640070L; + + /** + * For backward compatibility of the serialized {@code YearMonth.class} object, + * explicitly declare the types of the serialized fields as defined in Java SE 8. + * Instances of {@code YearMonth} are serialized using the dedicated + * serialized form by {@code writeReplace}. + * @serialField year int The year. + * @serialField month int The month-of-year. + */ + @java.io.Serial + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("year", int.class), + new ObjectStreamField("month", int.class), + }; /** * Parser. */ @@ -149,11 +167,11 @@ public final class YearMonth /** * @serial The year. */ - private final int year; + private final transient int year; /** - * @serial The month-of-year, not null. + * @serial The month-of-year.. */ - private final int month; + private final transient byte month; //----------------------------------------------------------------------- /** @@ -306,7 +324,7 @@ public final class YearMonth */ private YearMonth(int year, int month) { this.year = year; - this.month = month; + this.month = (byte) month; } /** @@ -1197,18 +1215,17 @@ public final class YearMonth public String toString() { int absYear = Math.abs(year); StringBuilder buf = new StringBuilder(9); - if (absYear < 1000) { + if (absYear < 10000) { if (year < 0) { - buf.append(year - 10000).deleteCharAt(1); - } else { - buf.append(year + 10000).deleteCharAt(0); + buf.append('-'); } + DecimalDigits.appendQuad(buf, absYear); } else { buf.append(year); } - return buf.append(month < 10 ? "-0" : "-") - .append(month) - .toString(); + buf.append('-'); + DecimalDigits.appendPair(buf, month); + return buf.toString(); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/ZoneOffset.java b/src/java.base/share/classes/java/time/ZoneOffset.java index 4199d17735c..2a45e7cbf82 100644 --- a/src/java.base/share/classes/java/time/ZoneOffset.java +++ b/src/java.base/share/classes/java/time/ZoneOffset.java @@ -88,6 +88,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReferenceArray; +import jdk.internal.util.DecimalDigits; import jdk.internal.vm.annotation.Stable; /** @@ -465,12 +466,14 @@ public final class ZoneOffset StringBuilder buf = new StringBuilder(); int absHours = absTotalSeconds / SECONDS_PER_HOUR; int absMinutes = (absTotalSeconds / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR; - buf.append(totalSeconds < 0 ? "-" : "+") - .append(absHours < 10 ? "0" : "").append(absHours) - .append(absMinutes < 10 ? ":0" : ":").append(absMinutes); + buf.append(totalSeconds < 0 ? '-' : '+'); + DecimalDigits.appendPair(buf, absHours); + buf.append(':'); + DecimalDigits.appendPair(buf, absMinutes); int absSeconds = absTotalSeconds % SECONDS_PER_MINUTE; if (absSeconds != 0) { - buf.append(absSeconds < 10 ? ":0" : ":").append(absSeconds); + buf.append(':'); + DecimalDigits.appendPair(buf, absSeconds); } return buf.toString(); } diff --git a/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java b/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java index ca226b70d24..67f08c5cb4f 100644 --- a/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java +++ b/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java @@ -74,6 +74,8 @@ import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Objects; +import jdk.internal.util.DecimalDigits; + /** * A date expressed in terms of a standard year-month-day calendar system. *

@@ -426,18 +428,22 @@ abstract class ChronoLocalDateImpl @Override public String toString() { - // getLong() reduces chances of exceptions in toString() - long yoe = getLong(YEAR_OF_ERA); - long moy = getLong(MONTH_OF_YEAR); - long dom = getLong(DAY_OF_MONTH); + // Using get() instead of getLong() for performance reasons, + // as the values of YEAR_OF_ERA, MONTH_OF_YEAR, and DAY_OF_MONTH + // are guaranteed to be within the int range for all chronologies. + int yoe = get(YEAR_OF_ERA); + int moy = get(MONTH_OF_YEAR); + int dom = get(DAY_OF_MONTH); StringBuilder buf = new StringBuilder(30); buf.append(getChronology().toString()) .append(" ") .append(getEra()) .append(" ") .append(yoe) - .append(moy < 10 ? "-0" : "-").append(moy) - .append(dom < 10 ? "-0" : "-").append(dom); + .append('-'); + DecimalDigits.appendPair(buf, moy); + buf.append('-'); + DecimalDigits.appendPair(buf, dom); return buf.toString(); } diff --git a/src/java.base/share/classes/java/time/chrono/HijrahDate.java b/src/java.base/share/classes/java/time/chrono/HijrahDate.java index 114a47e4797..2d3e4f93e69 100644 --- a/src/java.base/share/classes/java/time/chrono/HijrahDate.java +++ b/src/java.base/share/classes/java/time/chrono/HijrahDate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -137,11 +137,11 @@ public final class HijrahDate /** * The month-of-year. */ - private final transient int monthOfYear; + private final transient byte monthOfYear; /** * The day-of-month. */ - private final transient int dayOfMonth; + private final transient byte dayOfMonth; //------------------------------------------------------------------------- /** @@ -273,8 +273,8 @@ public final class HijrahDate this.chrono = chrono; this.prolepticYear = prolepticYear; - this.monthOfYear = monthOfYear; - this.dayOfMonth = dayOfMonth; + this.monthOfYear = (byte) monthOfYear; + this.dayOfMonth = (byte) dayOfMonth; } /** @@ -287,8 +287,8 @@ public final class HijrahDate this.chrono = chrono; this.prolepticYear = dateInfo[0]; - this.monthOfYear = dateInfo[1]; - this.dayOfMonth = dateInfo[2]; + this.monthOfYear = (byte) dateInfo[1]; + this.dayOfMonth = (byte) dateInfo[2]; } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/util/ArrayList.java b/src/java.base/share/classes/java/util/ArrayList.java index c00b130a553..53e818b99c5 100644 --- a/src/java.base/share/classes/java/util/ArrayList.java +++ b/src/java.base/share/classes/java/util/ArrayList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -750,9 +750,17 @@ public class ArrayList extends AbstractList * @throws NullPointerException if the specified collection is null */ public boolean addAll(Collection c) { - Object[] a = c.toArray(); + Object[] a; + int numNew; + if (c.getClass() == ArrayList.class) { + ArrayList src = (ArrayList) c; + a = src.elementData; + numNew = src.size; + } else { + a = c.toArray(); + numNew = a.length; + } modCount++; - int numNew = a.length; if (numNew == 0) return false; Object[] elementData; diff --git a/src/java.base/share/classes/java/util/Collections.java b/src/java.base/share/classes/java/util/Collections.java index c48dbd8cf6c..316458d6f90 100644 --- a/src/java.base/share/classes/java/util/Collections.java +++ b/src/java.base/share/classes/java/util/Collections.java @@ -5253,6 +5253,20 @@ public final class Collections { public int hashCode() { return Objects.hashCode(element); } + @Override + public Object[] toArray() { + return new Object[] {element}; + } + @Override + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + if (a.length < 1) + a = (T[])Array.newInstance(a.getClass().getComponentType(), 1); + a[0] = (T)element; + if (a.length > 1) + a[1] = null; + return a; + } } /** diff --git a/src/java.base/share/classes/java/util/Currency.java b/src/java.base/share/classes/java/util/Currency.java index febae04a77b..b254bae32a1 100644 --- a/src/java.base/share/classes/java/util/Currency.java +++ b/src/java.base/share/classes/java/util/Currency.java @@ -142,8 +142,8 @@ public final class Currency implements Serializable { // class data: instance map private static ConcurrentMap instances = new ConcurrentHashMap<>(7); - private static final Supplier> available = - StableValue.supplier(Currency::computeAllCurrencies); + private static final LazyConstant> available = + LazyConstant.of(Currency::computeAllCurrencies); // Class data: currency data obtained from currency.data file. // Purpose: diff --git a/src/java.base/share/classes/java/util/ImmutableCollections.java b/src/java.base/share/classes/java/util/ImmutableCollections.java index 1dd7808da20..abc48ff5ed9 100644 --- a/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -36,18 +36,12 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.IntFunction; import java.util.function.Predicate; -import java.util.function.Supplier; import java.util.function.UnaryOperator; import jdk.internal.access.JavaUtilCollectionAccess; import jdk.internal.access.SharedSecrets; -import jdk.internal.lang.stable.StableUtil; -import jdk.internal.lang.stable.StableValueImpl; import jdk.internal.misc.CDS; -import jdk.internal.util.ArraysSupport; -import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Stable; /** @@ -135,14 +129,6 @@ class ImmutableCollections { public List listFromTrustedArrayNullsAllowed(Object[] array) { return ImmutableCollections.listFromTrustedArrayNullsAllowed(array); } - public List stableList(int size, IntFunction mapper) { - // A stable list is not Serializable, so we cannot return `List.of()` if `size == 0` - return new StableList<>(size, mapper); - } - public Map stableMap(Set keys, Function mapper) { - // A stable map is not Serializable, so we cannot return `Map.of()` if `keys.isEmpty()` - return new StableMap<>(keys, mapper); - } }); } } @@ -450,7 +436,7 @@ class ImmutableCollections { } } - static sealed class SubList extends AbstractImmutableList + static final class SubList extends AbstractImmutableList implements RandomAccess { @Stable @@ -462,8 +448,10 @@ class ImmutableCollections { @Stable final int size; - private SubList(AbstractImmutableList root, int offset, int size) { - assert root instanceof List12 || root instanceof ListN || root instanceof StableList; + SubList(AbstractImmutableList root, int offset, int size) { + assert root instanceof List12 + || root instanceof ListN + || root instanceof LazyCollections.LazyList; this.root = root; this.offset = offset; this.size = size; @@ -795,187 +783,6 @@ class ImmutableCollections { } } - @FunctionalInterface - interface HasStableDelegates { - StableValueImpl[] delegates(); - } - - @jdk.internal.ValueBased - static final class StableList - extends AbstractImmutableList - implements HasStableDelegates { - - @Stable - private final IntFunction mapper; - @Stable - final StableValueImpl[] delegates; - - StableList(int size, IntFunction mapper) { - this.mapper = mapper; - this.delegates = StableUtil.array(size); - } - - @Override public boolean isEmpty() { return delegates.length == 0;} - @Override public int size() { return delegates.length; } - @Override public Object[] toArray() { return copyInto(new Object[size()]); } - - @ForceInline - @Override - public E get(int i) { - final StableValueImpl delegate; - try { - delegate = delegates[i]; - } catch (ArrayIndexOutOfBoundsException aioobe) { - throw new IndexOutOfBoundsException(i); - } - return delegate.orElseSet(new Supplier() { - @Override public E get() { return mapper.apply(i); }}); - } - - @Override - @SuppressWarnings("unchecked") - public T[] toArray(T[] a) { - final int size = delegates.length; - if (a.length < size) { - // Make a new array of a's runtime type, but my contents: - T[] n = (T[])Array.newInstance(a.getClass().getComponentType(), size); - return copyInto(n); - } - copyInto(a); - if (a.length > size) { - a[size] = null; // null-terminate - } - return a; - } - - @Override - public int indexOf(Object o) { - final int size = size(); - for (int i = 0; i < size; i++) { - if (Objects.equals(o, get(i))) { - return i; - } - } - return -1; - } - - @Override - public int lastIndexOf(Object o) { - for (int i = size() - 1; i >= 0; i--) { - if (Objects.equals(o, get(i))) { - return i; - } - } - return -1; - } - - @SuppressWarnings("unchecked") - private T[] copyInto(Object[] a) { - final int len = delegates.length; - for (int i = 0; i < len; i++) { - a[i] = get(i); - } - return (T[]) a; - } - - @Override - public List reversed() { - return new StableReverseOrderListView<>(this); - } - - @Override - public List subList(int fromIndex, int toIndex) { - subListRangeCheck(fromIndex, toIndex, size()); - return StableSubList.fromStableList(this, fromIndex, toIndex); - } - - @Override - public String toString() { - return StableUtil.renderElements(this, "StableCollection", delegates); - } - - @Override - public StableValueImpl[] delegates() { - return delegates; - } - - private static final class StableSubList extends SubList - implements HasStableDelegates { - - private StableSubList(AbstractImmutableList root, int offset, int size) { - super(root, offset, size); - } - - @Override - public List reversed() { - return new StableReverseOrderListView<>(this); - } - - @Override - public List subList(int fromIndex, int toIndex) { - subListRangeCheck(fromIndex, toIndex, size()); - return StableSubList.fromStableSubList(this, fromIndex, toIndex); - } - - @Override - public String toString() { - return StableUtil.renderElements(this, "StableCollection", delegates()); - } - - @Override - boolean allowNulls() { - return true; - } - - @Override - public StableValueImpl[] delegates() { - @SuppressWarnings("unchecked") - final var rootDelegates = ((HasStableDelegates) root).delegates(); - return Arrays.copyOfRange(rootDelegates, offset, offset + size); - } - - static SubList fromStableList(StableList list, int fromIndex, int toIndex) { - return new StableSubList<>(list, fromIndex, toIndex - fromIndex); - } - - static SubList fromStableSubList(StableSubList parent, int fromIndex, int toIndex) { - return new StableSubList<>(parent.root, parent.offset + fromIndex, toIndex - fromIndex); - } - - } - - private static final class StableReverseOrderListView - extends ReverseOrderListView.Rand - implements HasStableDelegates { - - private StableReverseOrderListView(List base) { - super(base, false); - } - - // This method does not evaluate the elements - @Override - public String toString() { - return StableUtil.renderElements(this, "StableCollection", delegates()); - } - - @Override - public List subList(int fromIndex, int toIndex) { - final int size = base.size(); - subListRangeCheck(fromIndex, toIndex, size); - return new StableReverseOrderListView<>(base.subList(size - toIndex, size - fromIndex)); - } - - @Override - public StableValueImpl[] delegates() { - @SuppressWarnings("unchecked") - final var baseDelegates = ((HasStableDelegates) base).delegates(); - return ArraysSupport.reverse( - Arrays.copyOf(baseDelegates, baseDelegates.length)); - } - } - - } - // ---------- Set Implementations ---------- @jdk.internal.ValueBased @@ -1614,187 +1421,6 @@ class ImmutableCollections { } } - static final class StableMap - extends AbstractImmutableMap { - - @Stable - private final Function mapper; - @Stable - private final Map> delegate; - - StableMap(Set keys, Function mapper) { - this.mapper = mapper; - this.delegate = StableUtil.map(keys); - } - - @Override public boolean containsKey(Object o) { return delegate.containsKey(o); } - @Override public int size() { return delegate.size(); } - @Override public Set> entrySet() { return StableMapEntrySet.of(this); } - - @ForceInline - @Override - public V get(Object key) { - return getOrDefault(key, null); - } - - @ForceInline - @Override - public V getOrDefault(Object key, V defaultValue) { - final StableValueImpl stable = delegate.get(key); - if (stable == null) { - return defaultValue; - } - @SuppressWarnings("unchecked") - final K k = (K) key; - return stable.orElseSet(new Supplier() { - @Override public V get() { return mapper.apply(k); }}); - } - - @jdk.internal.ValueBased - static final class StableMapEntrySet extends AbstractImmutableSet> { - - // Use a separate field for the outer class in order to facilitate - // a @Stable annotation. - @Stable - private final StableMap outer; - - @Stable - private final Set>> delegateEntrySet; - - private StableMapEntrySet(StableMap outer) { - this.outer = outer; - this.delegateEntrySet = outer.delegate.entrySet(); - } - - @Override public Iterator> iterator() { return LazyMapIterator.of(this); } - @Override public int size() { return delegateEntrySet.size(); } - @Override public int hashCode() { return outer.hashCode(); } - - @Override - public String toString() { - return StableUtil.renderMappings(this, "StableCollection", delegateEntrySet, false); - } - - // For @ValueBased - private static StableMapEntrySet of(StableMap outer) { - return new StableMapEntrySet<>(outer); - } - - @jdk.internal.ValueBased - static final class LazyMapIterator implements Iterator> { - - // Use a separate field for the outer class in order to facilitate - // a @Stable annotation. - @Stable - private final StableMapEntrySet outer; - - @Stable - private final Iterator>> delegateIterator; - - private LazyMapIterator(StableMapEntrySet outer) { - this.outer = outer; - this.delegateIterator = outer.delegateEntrySet.iterator(); - } - - @Override public boolean hasNext() { return delegateIterator.hasNext(); } - - @Override - public Entry next() { - final Map.Entry> inner = delegateIterator.next(); - final K k = inner.getKey(); - return new StableEntry<>(k, inner.getValue(), new Supplier() { - @Override public V get() { return outer.outer.mapper.apply(k); }}); - } - - @Override - public void forEachRemaining(Consumer> action) { - final Consumer>> innerAction = - new Consumer<>() { - @Override - public void accept(Entry> inner) { - final K k = inner.getKey(); - action.accept(new StableEntry<>(k, inner.getValue(), new Supplier() { - @Override public V get() { return outer.outer.mapper.apply(k); }})); - } - }; - delegateIterator.forEachRemaining(innerAction); - } - - // For @ValueBased - private static LazyMapIterator of(StableMapEntrySet outer) { - return new LazyMapIterator<>(outer); - } - - } - } - - private record StableEntry(K getKey, // trick - StableValueImpl stableValue, - Supplier supplier) implements Map.Entry { - - @Override public V setValue(V value) { throw uoe(); } - @Override public V getValue() { return stableValue.orElseSet(supplier); } - @Override public int hashCode() { return hash(getKey()) ^ hash(getValue()); } - @Override public String toString() { return getKey() + "=" + stableValue.toString(); } - @Override public boolean equals(Object o) { - return o instanceof Map.Entry e - && Objects.equals(getKey(), e.getKey()) - // Invoke `getValue()` as late as possible to avoid evaluation - && Objects.equals(getValue(), e.getValue()); - } - - private int hash(Object obj) { return (obj == null) ? 0 : obj.hashCode(); } - } - - @Override - public Collection values() { - return StableMapValues.of(this); - } - - @jdk.internal.ValueBased - static final class StableMapValues extends AbstractImmutableCollection { - - // Use a separate field for the outer class in order to facilitate - // a @Stable annotation. - @Stable - private final StableMap outer; - - private StableMapValues(StableMap outer) { - this.outer = outer; - } - - @Override public Iterator iterator() { return outer.new ValueIterator(); } - @Override public int size() { return outer.size(); } - @Override public boolean isEmpty() { return outer.isEmpty();} - @Override public boolean contains(Object v) { return outer.containsValue(v); } - - private static final IntFunction[]> GENERATOR = new IntFunction[]>() { - @Override - public StableValueImpl[] apply(int len) { - return new StableValueImpl[len]; - } - }; - - @Override - public String toString() { - final StableValueImpl[] values = outer.delegate.values().toArray(GENERATOR); - return StableUtil.renderElements(this, "StableCollection", values); - } - - // For @ValueBased - private static StableMapValues of(StableMap outer) { - return new StableMapValues<>(outer); - } - - } - - @Override - public String toString() { - return StableUtil.renderMappings(this, "StableMap", delegate.entrySet(), true); - } - - } - } // ---------- Serialization Proxy ---------- diff --git a/src/java.base/share/classes/java/util/LazyCollections.java b/src/java.base/share/classes/java/util/LazyCollections.java new file mode 100644 index 00000000000..0bbdad87ac4 --- /dev/null +++ b/src/java.base/share/classes/java/util/LazyCollections.java @@ -0,0 +1,584 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import jdk.internal.misc.Unsafe; +import jdk.internal.util.ImmutableBitSetPredicate; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; + +import java.lang.LazyConstant; +import java.lang.reflect.Array; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.IntFunction; +import java.util.function.IntPredicate; +import java.util.function.Supplier; + +/** + * Container class for lazy collections implementations. Not part of the public API. + */ +@AOTSafeClassInitializer +final class LazyCollections { + + /** + * No instances. + */ + private LazyCollections() { } + + // Unsafe allows LazyCollection classes to be used early in the boot sequence + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + @jdk.internal.ValueBased + static final class LazyList + extends ImmutableCollections.AbstractImmutableList { + + @Stable + private final E[] elements; + // Keeping track of `size` separately reduces bytecode size compared to + // using `elements.length`. + @Stable + private final int size; + @Stable + final FunctionHolder> functionHolder; + @Stable + private final Mutexes mutexes; + + private LazyList(int size, IntFunction computingFunction) { + this.elements = newGenericArray(size); + this.size = size; + this.functionHolder = new FunctionHolder<>(computingFunction, size); + this.mutexes = new Mutexes(size); + super(); + } + + @Override public boolean isEmpty() { return size == 0; } + @Override public int size() { return size; } + @Override public Object[] toArray() { return copyInto(new Object[size]); } + + @ForceInline + @Override + public E get(int i) { + final E e = contentsAcquire(offsetFor(Objects.checkIndex(i, size))); + return (e != null) ? e : getSlowPath(i); + } + + private E getSlowPath(int i) { + return orElseComputeSlowPath(elements, i, mutexes, i, functionHolder); + } + + @Override + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + if (a.length < size) { + // Make a new array of a's runtime type, but my contents: + T[] n = (T[]) Array.newInstance(a.getClass().getComponentType(), size); + return copyInto(n); + } + copyInto(a); + if (a.length > size) { + a[size] = null; // null-terminate + } + return a; + } + + @Override + public int indexOf(Object o) { + for (int i = 0; i < size; i++) { + if (Objects.equals(o, get(i))) { + return i; + } + } + return -1; + } + + @Override + public int lastIndexOf(Object o) { + for (int i = size - 1; i >= 0; i--) { + if (Objects.equals(o, get(i))) { + return i; + } + } + return -1; + } + + @SuppressWarnings("unchecked") + private T[] copyInto(Object[] a) { + for (int i = 0; i < size; i++) { + a[i] = get(i); + } + return (T[]) a; + } + + @SuppressWarnings("unchecked") + @ForceInline + private E contentsAcquire(long offset) { + return (E) UNSAFE.getReferenceAcquire(elements, offset); + } + + } + + static final class LazyEnumMap, V> + extends AbstractLazyMap { + + @Stable + private final Class enumType; + @Stable + // We are using a wrapper class here to be able to use a min value of zero that + // is also stable. + private final Integer min; + @Stable + private final IntPredicate member; + + public LazyEnumMap(Set set, + Class enumType, + int min, + int backingSize, + IntPredicate member, + Function computingFunction) { + this.enumType = enumType; + this.min = min; + this.member = member; + super(set, set.size(), backingSize, computingFunction); + } + + @Override + @ForceInline + public boolean containsKey(Object o) { + return enumType.isAssignableFrom(o.getClass()) + && member.test(((Enum) o).ordinal()); + } + + @ForceInline + @Override + public V getOrDefault(Object key, V defaultValue) { + if (enumType.isAssignableFrom(key.getClass())) { + final int ordinal = ((Enum) key).ordinal(); + if (member.test(ordinal)) { + @SuppressWarnings("unchecked") + final K k = (K) key; + return orElseCompute(k, indexForAsInt(k)); + } + } + return defaultValue; + } + + @Override + Integer indexFor(K key) { + return indexForAsInt(key); + } + + private int indexForAsInt(K key) { + return key.ordinal() - min; + } + + } + + static final class LazyMap + extends AbstractLazyMap { + + // Use an unmodifiable map with known entries that are @Stable. Lookups through this map can be folded because + // it is created using Map.ofEntrie. This allows us to avoid creating a separate hashing function. + @Stable + private final Map indexMapper; + + public LazyMap(Set keys, Function computingFunction) { + @SuppressWarnings("unchecked") + final Entry[] entries = (Entry[]) new Entry[keys.size()]; + int i = 0; + for (K k : keys) { + entries[i] = Map.entry(k, i++); + } + this.indexMapper = Map.ofEntries(entries); + super(keys, i, i, computingFunction); + } + + @ForceInline + @Override + public V getOrDefault(Object key, V defaultValue) { + final Integer index = indexMapper.get(key); + if (index != null) { + @SuppressWarnings("unchecked") + final K k = (K) key; + return orElseCompute(k, index); + } + return defaultValue; + } + + @Override public boolean containsKey(Object o) { return indexMapper.containsKey(o); } + + @Override + Integer indexFor(K key) { + return indexMapper.get(key); + } + } + + static sealed abstract class AbstractLazyMap + extends ImmutableCollections.AbstractImmutableMap { + + // This field shadows AbstractMap.keySet which is not @Stable. + @Stable + Set keySet; + // This field shadows AbstractMap.values which is of another type + @Stable + final V[] values; + @Stable + Mutexes mutexes; + @Stable + private final int size; + @Stable + final FunctionHolder> functionHolder; + @Stable + private final Set> entrySet; + + private AbstractLazyMap(Set keySet, + int size, + int backingSize, + Function computingFunction) { + this.size = size; + this.functionHolder = new FunctionHolder<>(computingFunction, size); + this.values = newGenericArray(backingSize); + this.mutexes = new Mutexes(backingSize); + super(); + this.keySet = keySet; + this.entrySet = LazyMapEntrySet.of(this); + } + + // Abstract methods + @Override public abstract boolean containsKey(Object o); + abstract Integer indexFor(K key); + + // Public methods + @Override public final int size() { return size; } + @Override public final boolean isEmpty() { return size == 0; } + @Override public final Set> entrySet() { return entrySet; } + @Override public Set keySet() { return keySet; } + + @ForceInline + @Override + public final V get(Object key) { + return getOrDefault(key, null); + } + + @SuppressWarnings("unchecked") + @ForceInline + final V orElseCompute(K key, int index) { + final long offset = offsetFor(index); + final V v = (V) UNSAFE.getReferenceAcquire(values, offset); + if (v != null) { + return v; + } + return orElseComputeSlowPath(values, index, mutexes, key, functionHolder); + } + + @jdk.internal.ValueBased + static final class LazyMapEntrySet extends ImmutableCollections.AbstractImmutableSet> { + + // Use a separate field for the outer class in order to facilitate + // a @Stable annotation. + @Stable + private final AbstractLazyMap map; + + private LazyMapEntrySet(AbstractLazyMap map) { + this.map = map; + super(); + } + + @Override public Iterator> iterator() { return LazyMapIterator.of(map); } + @Override public int size() { return map.size(); } + @Override public int hashCode() { return map.hashCode(); } + + // For @ValueBased + private static LazyMapEntrySet of(AbstractLazyMap outer) { + return new LazyMapEntrySet<>(outer); + } + + @jdk.internal.ValueBased + static final class LazyMapIterator implements Iterator> { + + // Use a separate field for the outer class in order to facilitate + // a @Stable annotation. + @Stable + private final AbstractLazyMap map; + @Stable + private final Iterator keyIterator; + + private LazyMapIterator(AbstractLazyMap map) { + this.map = map; + this.keyIterator = map.keySet.iterator(); + super(); + } + + @Override public boolean hasNext() { return keyIterator.hasNext(); } + + @Override + public Entry next() { + final K k = keyIterator.next(); + return new LazyEntry<>(k, map, map.functionHolder); + } + + @Override + public void forEachRemaining(Consumer> action) { + final Consumer innerAction = + new Consumer<>() { + @Override + public void accept(K key) { + action.accept(new LazyEntry<>(key, map, map.functionHolder)); + } + }; + keyIterator.forEachRemaining(innerAction); + } + + // For @ValueBased + private static LazyMapIterator of(AbstractLazyMap map) { + return new LazyMapIterator<>(map); + } + + } + } + + private record LazyEntry(K getKey, // trick + AbstractLazyMap map, + FunctionHolder> functionHolder) implements Entry { + + @Override public V setValue(V value) { throw ImmutableCollections.uoe(); } + @Override public V getValue() { return map.orElseCompute(getKey, map.indexFor(getKey)); } + @Override public int hashCode() { return hash(getKey()) ^ hash(getValue()); } + @Override public String toString() { return getKey() + "=" + getValue(); } + + @Override + public boolean equals(Object o) { + return o instanceof Map.Entry e + && Objects.equals(getKey(), e.getKey()) + // Invoke `getValue()` as late as possible to avoid evaluation + && Objects.equals(getValue(), e.getValue()); + } + + private int hash(Object obj) { + return (obj == null) ? 0 : obj.hashCode(); + } + } + + @Override + public Collection values() { + return LazyMapValues.of(this); + } + + @jdk.internal.ValueBased + static final class LazyMapValues extends ImmutableCollections.AbstractImmutableCollection { + + // Use a separate field for the outer class in order to facilitate + // a @Stable annotation. + @Stable + private final AbstractLazyMap map; + + private LazyMapValues(AbstractLazyMap map) { + this.map = map; + super(); + } + + @Override public Iterator iterator() { return map.new ValueIterator(); } + @Override public int size() { return map.size(); } + @Override public boolean isEmpty() { return map.isEmpty(); } + @Override public boolean contains(Object v) { return map.containsValue(v); } + + // For @ValueBased + private static LazyMapValues of(AbstractLazyMap outer) { + return new LazyMapValues<>(outer); + } + + } + + } + + static final class Mutexes { + + private static final Object TOMB_STONE = new Object(); + + // Filled on demand and then discarded once it is not needed anymore. + // A mutex element can only transition like so: `null` -> `new Object()` -> `TOMB_STONE` + private volatile Object[] mutexes; + // Used to detect we have computed all elements and no longer need the `mutexes` array + private volatile AtomicInteger counter; + + private Mutexes(int length) { + this.mutexes = new Object[length]; + this.counter = new AtomicInteger(length); + } + + @ForceInline + private Object acquireMutex(long offset) { + assert mutexes != null; + // Check if there already is a mutex (Object or TOMB_STONE) + final Object mutex = UNSAFE.getReferenceVolatile(mutexes, offset); + if (mutex != null) { + return mutex; + } + // Protect against racy stores of mutex candidates + final Object candidate = new Object(); + final Object witness = UNSAFE.compareAndExchangeReference(mutexes, offset, null, candidate); + return witness == null ? candidate : witness; + } + + private void releaseMutex(long offset) { + // Replace the old mutex with a tomb stone since now the old mutex can be collected. + UNSAFE.putReference(mutexes, offset, TOMB_STONE); + if (counter != null && counter.decrementAndGet() == 0) { + mutexes = null; + counter = null; + } + } + + } + + @ForceInline + private static long offsetFor(long index) { + return Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * index; + } + + @SuppressWarnings("unchecked") + private static E[] newGenericArray(int length) { + return (E[]) new Object[length]; + } + + public static List ofLazyList(int size, + IntFunction computingFunction) { + return new LazyList<>(size, computingFunction); + } + + public static Map ofLazyMap(Set keys, + Function computingFunction) { + return new LazyMap<>(keys, computingFunction); + } + + @SuppressWarnings("unchecked") + public static , V> + Map ofLazyMapWithEnumKeys(Set keys, + Function computingFunction) { + // The input set is not empty + final Class enumType = ((E) keys.iterator().next()).getDeclaringClass(); + final BitSet bitSet = new BitSet(enumType.getEnumConstants().length); + int min = Integer.MAX_VALUE; + int max = Integer.MIN_VALUE; + for (K t : keys) { + final int ordinal = ((E) t).ordinal(); + min = Math.min(min, ordinal); + max = Math.max(max, ordinal); + bitSet.set(ordinal); + } + final int backingSize = max - min + 1; + final IntPredicate member = ImmutableBitSetPredicate.of(bitSet); + return (Map) new LazyEnumMap<>((Set) keys, enumType, min, backingSize, member, (Function) computingFunction); + } + + @SuppressWarnings("unchecked") + static T orElseComputeSlowPath(final T[] array, + final int index, + final Mutexes mutexes, + final Object input, + final FunctionHolder functionHolder) { + final long offset = offsetFor(index); + final Object mutex = mutexes.acquireMutex(offset); + preventReentry(mutex); + synchronized (mutex) { + final T t = array[index]; // Plain semantics suffice here + if (t == null) { + final T newValue = switch (functionHolder.function()) { + case IntFunction iFun -> (T) iFun.apply((int) input); + case Function fun -> ((Function) fun).apply(input); + default -> throw new InternalError("cannot reach here"); + }; + Objects.requireNonNull(newValue); + // Reduce the counter and if it reaches zero, clear the reference + // to the underlying holder. + functionHolder.countDown(); + + // The mutex is not reentrant so we know newValue should be returned + set(array, index, mutex, newValue); + // We do not need the mutex anymore + mutexes.releaseMutex(offset); + return newValue; + } + return t; + } + } + + static void preventReentry(Object mutex) { + if (Thread.holdsLock(mutex)) { + throw new IllegalStateException("Recursive initialization of a lazy collection is illegal"); + } + } + + static void set(T[] array, int index, Object mutex, T newValue) { + assert Thread.holdsLock(mutex) : index + "didn't hold " + mutex; + // We know we hold the monitor here so plain semantic is enough + // This is an extra safety net to emulate a CAS op. + if (array[index] == null) { + UNSAFE.putReferenceRelease(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * (long) index, newValue); + } + } + + /** + * This class is thread safe. Any thread can create and use an instance of this class at + * any time. The `function` field is only accessed if `counter` is positive so the setting + * of function to `null` is safe. + * + * @param the underlying function type + */ + @AOTSafeClassInitializer + static final class FunctionHolder { + + private static final long COUNTER_OFFSET = UNSAFE.objectFieldOffset(FunctionHolder.class, "counter"); + + // This field can only transition at most once from being set to a + // non-null reference to being `null`. Once `null`, it is never read. + private U function; + // Used reflectively via Unsafe + private int counter; + + public FunctionHolder(U function, int counter) { + this.function = (counter == 0) ? null : function; + this.counter = counter; + // Safe publication + UNSAFE.storeStoreFence(); + } + + @ForceInline + public U function() { + return function; + } + + public void countDown() { + if (UNSAFE.getAndAddInt(this, COUNTER_OFFSET, -1) == 1) { + // Do not reference the underlying function anymore so it can be collected. + function = null; + } + } + } + +} diff --git a/src/java.base/share/classes/java/util/List.java b/src/java.base/share/classes/java/util/List.java index 32430298363..43408de292a 100644 --- a/src/java.base/share/classes/java/util/List.java +++ b/src/java.base/share/classes/java/util/List.java @@ -25,6 +25,11 @@ package java.util; +import jdk.internal.foreign.Utils; +import jdk.internal.javac.PreviewFeature; + +import java.io.Serializable; +import java.util.function.IntFunction; import java.util.function.UnaryOperator; /** @@ -87,9 +92,9 @@ import java.util.function.UnaryOperator; * interface. * *

Unmodifiable Lists

- *

The {@link List#of(Object...) List.of} and - * {@link List#copyOf List.copyOf} static factory methods - * provide a convenient way to create unmodifiable lists. The {@code List} + *

The {@link List#of(Object...) List.of}, + * {@link List#copyOf List.copyOf}, and {@link List#ofLazy(int, IntFunction)} static + * factory methods provide a convenient way to create unmodifiable lists. The {@code List} * instances created by these methods have the following characteristics: * *

    @@ -100,7 +105,7 @@ import java.util.function.UnaryOperator; * this may cause the List's contents to appear to change. *
  • They disallow {@code null} elements. Attempts to create them with * {@code null} elements result in {@code NullPointerException}. - *
  • They are serializable if all elements are serializable. + *
  • Unless otherwise specified, they are serializable if all elements are serializable. *
  • The order of elements in the list is the same as the order of the * provided arguments, or of the elements in the provided array. *
  • The lists and their {@link #subList(int, int) subList} views implement the @@ -1190,4 +1195,71 @@ public interface List extends SequencedCollection { static List copyOf(Collection coll) { return ImmutableCollections.listCopy(coll); } + + /** + * {@return a new lazily computed list of the provided {@code size}} + *

    + * The returned list is an {@linkplain Collection##unmodifiable unmodifiable} list + * with the provided {@code size}. The list's elements are lazily computed via the + * provided {@code computingFunction} when they are first accessed + * (e.g., via {@linkplain List#get(int) List::get}). + *

    + * The provided computing function is guaranteed to be successfully + * invoked at most once per list index, even in a multi-threaded environment. + * Competing threads accessing an element already under computation will block until + * an element is computed or the computing function completes abnormally. + *

    + * If invoking the provided computing function throws an exception, it is rethrown + * to the initial caller and no value for the element is recorded. + *

    + * If the provided computing function returns {@code null}, + * a {@linkplain NullPointerException} will be thrown. Hence, just like other + * unmodifiable lists created via the {@code List::of} factories, a lazy list + * cannot contain {@code null} elements. Clients that want to use nullable elements + * can wrap elements into an {@linkplain Optional} holder. + *

    + * The elements of any {@link List#subList(int, int) subList()} or + * {@link List#reversed()} views of the returned list are also lazily computed. + *

    + * The returned list and its {@link List#subList(int, int) subList()} or + * {@link List#reversed()} views implement the {@link RandomAccess} interface. + *

    + * If the provided computing function recursively calls itself or the returned + * lazy list for the same index, an {@linkplain IllegalStateException} + * will be thrown. + *

    + * The returned list's {@linkplain Object Object methods}; + * {@linkplain Object#equals(Object) equals()}, + * {@linkplain Object#hashCode() hashCode()}, and + * {@linkplain Object#toString() toString()} methods may trigger initialization of + * one or more lazy elements. + *

    + * The returned lazy list strongly references its computing + * function used to compute elements at least as long as there are uninitialized + * elements. + *

    + * The returned List is not {@linkplain Serializable}. + * + * @implNote after all elements have been initialized successfully, the computing + * function is no longer strongly referenced and becomes eligible for + * garbage collection. + * + * @param size the size of the returned lazy list + * @param computingFunction to invoke whenever an element is first accessed + * (may not return {@code null}) + * @param the type of elements in the returned list + * @throws IllegalArgumentException if the provided {@code size} is negative. + * + * @see LazyConstant + * @since 26 + */ + @PreviewFeature(feature = PreviewFeature.Feature.LAZY_CONSTANTS) + static List ofLazy(int size, + IntFunction computingFunction) { + Utils.checkNonNegativeArgument(size, "size"); + Objects.requireNonNull(computingFunction); + // A computed list is not Serializable, so we cannot return `List.of()` if `size == 0` + return LazyCollections.ofLazyList(size, computingFunction); + } + } diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 97278cdbafa..54863d58782 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -992,8 +992,8 @@ public final class Locale implements Cloneable, Serializable { } } - private static final Supplier> LOCALE_CACHE = - StableValue.supplier(new Supplier<>() { + private static final LazyConstant> LOCALE_CACHE = + LazyConstant.of(new Supplier<>() { @Override public ReferencedKeyMap get() { return ReferencedKeyMap.create(true, ReferencedKeyMap.concurrentHashMapSupplier()); @@ -2330,8 +2330,8 @@ public final class Locale implements Cloneable, Serializable { private static volatile Locale defaultDisplayLocale; private static volatile Locale defaultFormatLocale; - private final transient Supplier languageTag = - StableValue.supplier(new Supplier<>() { + private final transient LazyConstant languageTag = + LazyConstant.of(new Supplier<>() { @Override public String get() { return computeLanguageTag(); diff --git a/src/java.base/share/classes/java/util/LocaleISOData.java b/src/java.base/share/classes/java/util/LocaleISOData.java index 29e0b28be01..c99e88bd2bd 100644 --- a/src/java.base/share/classes/java/util/LocaleISOData.java +++ b/src/java.base/share/classes/java/util/LocaleISOData.java @@ -30,32 +30,32 @@ import java.util.function.Supplier; // Methods and suppliers for producing ISO 639/3166 resources used by Locale. class LocaleISOData { - static final Supplier ISO_639 = - StableValue.supplier(new Supplier<>() { + static final LazyConstant ISO_639 = + LazyConstant.of(new Supplier<>() { @Override public String[] get() { return getISO2Table(isoLanguageTable); } }); - static final Supplier ISO_3166_1_ALPHA2 = - StableValue.supplier(new Supplier<>() { + static final LazyConstant ISO_3166_1_ALPHA2 = + LazyConstant.of(new Supplier<>() { @Override public String[] get() { return getISO2Table(isoCountryTable); } }); - static final Supplier> ISO_3166_1_ALPHA3 = - StableValue.supplier(new Supplier<>() { + static final LazyConstant> ISO_3166_1_ALPHA3 = + LazyConstant.of(new Supplier<>() { @Override public Set get() { return computeISO3166_1Alpha3Countries(); } }); - static final Supplier> ISO_3166_3 = - StableValue.supplier(new Supplier<>() { + static final LazyConstant> ISO_3166_3 = + LazyConstant.of(new Supplier<>() { @Override public Set get() { return Set.of(ISO3166_3); diff --git a/src/java.base/share/classes/java/util/Map.java b/src/java.base/share/classes/java/util/Map.java index fbb41be5073..177f0522b1b 100644 --- a/src/java.base/share/classes/java/util/Map.java +++ b/src/java.base/share/classes/java/util/Map.java @@ -25,6 +25,8 @@ package java.util; +import jdk.internal.javac.PreviewFeature; + import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; @@ -114,8 +116,9 @@ import java.io.Serializable; * *

    Unmodifiable Maps

    *

    The {@link Map#of() Map.of}, - * {@link Map#ofEntries(Map.Entry...) Map.ofEntries}, and - * {@link Map#copyOf Map.copyOf} + * {@link Map#ofEntries(Map.Entry...) Map.ofEntries}, + * {@link Map#copyOf Map.copyOf}, and + * {@link Map#ofLazy(Set, Function)} * static factory methods provide a convenient way to create unmodifiable maps. * The {@code Map} * instances created by these methods have the following characteristics: @@ -128,7 +131,8 @@ import java.io.Serializable; * Map to behave inconsistently or its contents to appear to change. *

  • They disallow {@code null} keys and values. Attempts to create them with * {@code null} keys or values result in {@code NullPointerException}. - *
  • They are serializable if all keys and values are serializable. + *
  • Unless otherwise specified, they are serializable if all keys and values + * are serializable. *
  • They reject duplicate keys at creation time. Duplicate keys * passed to a static factory method result in {@code IllegalArgumentException}. *
  • The iteration order of mappings is unspecified and is subject to change. @@ -1746,4 +1750,79 @@ public interface Map { return (Map)Map.ofEntries(map.entrySet().toArray(new Entry[0])); } } + + /** + * {@return a new lazily computed map with the provided {@code keys}} + *

    + * The returned map is an {@linkplain Collection##unmodifiable unmodifiable} map whose + * keys are known at construction. The map's values are lazily computed via the + * provided {@code computingFunction} when they are first accessed + * (e.g., via {@linkplain Map#get(Object) Map::get}). + *

    + * The provided computing function is guaranteed to be successfully invoked + * at most once per key, even in a multi-threaded environment. Competing + * threads accessing a value already under computation will block until an element + * is computed or the computing function completes abnormally. + *

    + * If invoking the provided computing function throws an exception, it + * is rethrown to the initial caller and no value associated with the provided key + * is recorded. + *

    + * If the provided computing function returns {@code null}, + * a {@linkplain NullPointerException} will be thrown. Hence, just like other + * unmodifiable maps created via the {@code Map::of} factories, a lazy map + * cannot contain {@code null} values. Clients that want to use nullable values can + * wrap values into an {@linkplain Optional} holder. + *

    + * The values of any {@link Map#values()} or {@link Map#entrySet()} views of + * the returned map are also lazily computed. + *

    + * If the provided computing function recursively calls itself or + * the returned lazy map for the same key, an {@linkplain IllegalStateException} + * will be thrown. + *

    + * The returned map's {@linkplain Object Object methods}; + * {@linkplain Object#equals(Object) equals()}, + * {@linkplain Object#hashCode() hashCode()}, and + * {@linkplain Object#toString() toString()} methods may trigger initialization of + * one or more lazy elements. + *

    + * The returned lazy map strongly references its underlying + * computing function used to compute values at least as long as there are + * uncomputed values. + *

    + * The returned Map is not {@linkplain Serializable}. + * + * @implNote after all values have been initialized successfully, the computing + * function is no longer strongly referenced and becomes eligible for + * garbage collection. + * + * @param keys the (non-null) keys in the returned computed map + * @param computingFunction to invoke whenever an associated value is first accessed + * @param the type of keys maintained by the returned map + * @param the type of mapped values in the returned map + * @throws NullPointerException if the provided set of {@code keys} is {@code null} + * or if the set of {@code keys} contains a {@code null} element. + * + * @see LazyConstant + * @since 26 + */ + @PreviewFeature(feature = PreviewFeature.Feature.LAZY_CONSTANTS) + static Map ofLazy(Set keys, + Function computingFunction) { + // Protect against TOC-TOU attacks. + // Also, implicit null check of `keys` and all its elements + final Set keyCopies = Set.copyOf(keys); + Objects.requireNonNull(computingFunction); + // We need to check the instance type using the original `keys` parameter. + if (keys instanceof EnumSet && !keyCopies.isEmpty()) { + @SuppressWarnings("unchecked") + var enumMap = (Map) LazyCollections.ofLazyMapWithEnumKeys(keyCopies, computingFunction); + return enumMap; + } else { + // A computed map is not Serializable, so we cannot return `Map.of()` if `keys.isEmpty()` + return LazyCollections.ofLazyMap(keyCopies, computingFunction); + } + } + } diff --git a/src/java.base/share/classes/java/util/Optional.java b/src/java.base/share/classes/java/util/Optional.java index e19dde6383e..3e577bd379c 100644 --- a/src/java.base/share/classes/java/util/Optional.java +++ b/src/java.base/share/classes/java/util/Optional.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -22,8 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package java.util; +import jdk.internal.vm.annotation.Stable; + import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -68,6 +71,7 @@ public final class Optional { /** * If non-null, the value; if null, indicates no value is present */ + @Stable private final T value; /** diff --git a/src/java.base/share/classes/java/util/ResourceBundle.java b/src/java.base/share/classes/java/util/ResourceBundle.java index b375a8ba941..db19eda6399 100644 --- a/src/java.base/share/classes/java/util/ResourceBundle.java +++ b/src/java.base/share/classes/java/util/ResourceBundle.java @@ -488,7 +488,7 @@ public abstract class ResourceBundle { /** * A Set of the keys contained only in this ResourceBundle. */ - private final Supplier> keySet = StableValue.supplier( + private final LazyConstant> keySet = LazyConstant.of( new Supplier<>() { public Set get() { return keySet0(); }}); private Set keySet0() { diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java index 4cb7048a798..9295f0deb59 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java @@ -1372,12 +1372,20 @@ public class ConcurrentHashMap extends AbstractMap Node[] t; int f = (t = table) == null ? 0 : t.length; Traverser it = new Traverser(t, f, 0, f); - for (Node p; (p = it.advance()) != null; ) { - V val = p.val; - Object v = m.get(p.key); - if (v == null || (v != val && !v.equals(val))) - return false; + + try { + for (Node p; (p = it.advance()) != null; ) { + V val = p.val; + Object v = m.get(p.key); + if (v == null || (v != val && !v.equals(val))) + return false; + } + } catch (ClassCastException | NullPointerException _) { + // m.get(p.key) is contractually allowed to throw CCE or NPE + // but CHM doesn't allow null keys, so NPE shouldn't occur in practice + return false; } + for (Map.Entry e : m.entrySet()) { Object mk, mv, v; if ((mk = e.getKey()) == null || diff --git a/src/java.base/share/classes/java/util/concurrent/DelayScheduler.java b/src/java.base/share/classes/java/util/concurrent/DelayScheduler.java index d1f8283489b..1ded0211932 100644 --- a/src/java.base/share/classes/java/util/concurrent/DelayScheduler.java +++ b/src/java.base/share/classes/java/util/concurrent/DelayScheduler.java @@ -360,31 +360,36 @@ final class DelayScheduler extends Thread { u.heapIndex = -1; } } - if (t != null) { // sift down - for (int cs; (cs = (k << 2) + 1) < n; ) { - ScheduledForkJoinTask leastChild = null, c; + if (t != null) { + while (k > 0) { // sift up if replaced with smaller value + ScheduledForkJoinTask parent; int pk; + if ((parent = h[pk = (k - 1) >>> 2]) == null || + parent.when <= d) + break; + parent.heapIndex = k; + h[k] = parent; + k = pk; + } + for (int cs; (cs = (k << 2) + 1) < n; ) { // sift down + ScheduledForkJoinTask leastChild = null; int leastIndex = 0; - long leastValue = Long.MAX_VALUE; - for (int ck = cs, j = 4;;) { // at most 4 children - if ((c = h[ck]) == null) - break; - long cd = c.when; - if (c.status < 0 && alsoReplace < 0) { - alsoReplace = ck; // at most once per pass - c.heapIndex = -1; - } - else if (leastChild == null || cd < leastValue) { + long leastValue = d; // at most 4 children + for (int ck, j = 0; j < 4 && (ck = j + cs) < n; ++j) { + ScheduledForkJoinTask c; long cd; + if ((c = h[ck]) != null && (cd = c.when) < leastValue) { leastValue = cd; leastIndex = ck; leastChild = c; } - if (--j == 0 || ++ck >= n) - break; } - if (leastChild == null || d <= leastValue) + if (leastChild == null) // already ordered break; - leastChild.heapIndex = k; - h[k] = leastChild; + if ((h[k] = leastChild).status >= 0 || alsoReplace >= 0) + leastChild.heapIndex = k; + else { + leastChild.heapIndex = -1; + alsoReplace = k; + } k = leastIndex; } t.heapIndex = k; @@ -393,6 +398,7 @@ final class DelayScheduler extends Thread { k = alsoReplace; } } + assert checkHeap(h, n); return n; } @@ -451,6 +457,33 @@ final class DelayScheduler extends Thread { } } + /** + * Invariant checks + */ + private static boolean checkHeap(ScheduledForkJoinTask[] h, int n) { + for (int i = 0; i < h.length; ++i) { + ScheduledForkJoinTask t = h[i]; + if (t == null) { // unused slots all null + if (i < n) + return false; + } + else { + long v = t.when; + int x = t.heapIndex; + if (x != i && x >= 0) // valid index unless removing + return false; + if (i > 0 && h[(i - 1) >>> 2].when > v) // ordered wrt parent + return false; + int cs = (i << 2) + 1; // ordered wrt children + for (int ck, j = 0; j < 4 && (ck = cs + j) < n; ++j) { + if (h[ck].when < v) + return false; + } + } + } + return true; + } + /** * Task class for DelayScheduler operations */ diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index 1f2c8d2ffa6..f289186e0ad 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -560,89 +560,70 @@ public class ForkJoinPool extends AbstractExecutorService * access (which is usually needed anyway). * * Signalling. Signals (in signalWork) cause new or reactivated - * workers to scan for tasks. Method signalWork and its callers - * try to approximate the unattainable goal of having the right - * number of workers activated for the tasks at hand, but must err - * on the side of too many workers vs too few to avoid stalls: + * workers to scan for tasks. SignalWork is invoked in two cases: + * (1) When a task is pushed onto an empty queue, and (2) When a + * worker takes a top-level task from a queue that has additional + * tasks. Together, these suffice in O(log(#threads)) steps to + * fully activate with at least enough workers, and ideally no + * more than required. This ideal is unobtainable: Callers do not + * know whether another worker will finish its current task and + * poll for others without need of a signal (which is otherwise an + * advantage of work-stealing vs other schemes), and also must + * conservatively estimate the triggering conditions of emptiness + * or non-emptiness; all of which usually cause more activations + * than necessary (see below). (Method signalWork is also used as + * failsafe in case of Thread failures in deregisterWorker, to + * activate or create a new worker to replace them). * - * * If computations are purely tree structured, it suffices for - * every worker to activate another when it pushes a task into - * an empty queue, resulting in O(log(#threads)) steps to full - * activation. Emptiness must be conservatively approximated, - * which may result in unnecessary signals. Also, to reduce - * resource usages in some cases, at the expense of slower - * startup in others, activation of an idle thread is preferred - * over creating a new one, here and elsewhere. - * - * * At the other extreme, if "flat" tasks (those that do not in - * turn generate others) come in serially from only a single - * producer, each worker taking a task from a queue should - * propagate a signal if there are more tasks in that - * queue. This is equivalent to, but generally faster than, - * arranging the stealer take multiple tasks, re-pushing one or - * more on its own queue, and signalling (because its queue is - * empty), also resulting in logarithmic full activation - * time. If tasks do not not engage in unbounded loops based on - * the actions of other workers with unknown dependencies loop, - * this form of proagation can be limited to one signal per - * activation (phase change). We distinguish the cases by - * further signalling only if the task is an InterruptibleTask - * (see below), which are the only supported forms of task that - * may do so. - * - * * Because we don't know about usage patterns (or most commonly, - * mixtures), we use both approaches, which present even more - * opportunities to over-signal. (Failure to distinguish these - * cases in terms of submission methods was arguably an early - * design mistake.) Note that in either of these contexts, - * signals may be (and often are) unnecessary because active - * workers continue scanning after running tasks without the - * need to be signalled (which is one reason work stealing is - * often faster than alternatives), so additional workers - * aren't needed. - * - * * For rapidly branching tasks that require full pool resources, - * oversignalling is OK, because signalWork will soon have no - * more workers to create or reactivate. But for others (mainly - * externally submitted tasks), overprovisioning may cause very - * noticeable slowdowns due to contention and resource - * wastage. We reduce impact by deactivating workers when - * queues don't have accessible tasks, but reactivating and - * rescanning if other tasks remain. - * - * * Despite these, signal contention and overhead effects still - * occur during ramp-up and ramp-down of small computations. + * Top-Level scheduling + * ==================== * * Scanning. Method runWorker performs top-level scanning for (and * execution of) tasks by polling a pseudo-random permutation of * the array (by starting at a given index, and using a constant * cyclically exhaustive stride.) It uses the same basic polling * method as WorkQueue.poll(), but restarts with a different - * permutation on each invocation. The pseudorandom generator - * need not have high-quality statistical properties in the long + * permutation on each rescan. The pseudorandom generator need + * not have high-quality statistical properties in the long * term. We use Marsaglia XorShifts, seeded with the Weyl sequence - * from ThreadLocalRandom probes, which are cheap and - * suffice. Each queue's polling attempts to avoid becoming stuck - * when other scanners/pollers stall. Scans do not otherwise - * explicitly take into account core affinities, loads, cache - * localities, etc, However, they do exploit temporal locality - * (which usually approximates these) by preferring to re-poll - * from the same queue after a successful poll before trying - * others, which also reduces bookkeeping, cache traffic, and - * scanning overhead. But it also reduces fairness, which is - * partially counteracted by giving up on detected interference - * (which also reduces contention when too many workers try to - * take small tasks from the same queue). + * from ThreadLocalRandom probes, which are cheap and suffice. * * Deactivation. When no tasks are found by a worker in runWorker, - * it tries to deactivate()), giving up (and rescanning) on "ctl" - * contention. To avoid missed signals during deactivation, the - * method rescans and reactivates if there may have been a missed - * signal during deactivation. To reduce false-alarm reactivations - * while doing so, we scan multiple times (analogously to method - * quiescent()) before trying to reactivate. Because idle workers - * are often not yet blocked (parked), we use a WorkQueue field to - * advertise that a waiter actually needs unparking upon signal. + * it invokes deactivate, that first deactivates (to an IDLE + * phase). Avoiding missed signals during deactivation requires a + * (conservative) rescan, reactivating if there may be tasks to + * poll. Because idle workers are often not yet blocked (parked), + * we use a WorkQueue field to advertise that a waiter actually + * needs unparking upon signal. + * + * When tasks are constructed as (recursive) DAGs, top-level + * scanning is usually infrequent, and doesn't encounter most + * of the following problems addressed by runWorker and awaitWork: + * + * Locality. Polls are organized into "runs", continuing until + * empty or contended, while also minimizing interference by + * postponing bookeeping to ends of runs. This may reduce + * fairness. + * + * Contention. When many workers try to poll few queues, they + * often collide, generating CAS failures and disrupting locality + * of workers already running their tasks. This also leads to + * stalls when tasks cannot be taken because other workers have + * not finished poll operations, which is detected by reading + * ahead in queue arrays. In both cases, workers restart scans in a + * way that approximates randomized backoff. + * + * Oversignalling. When many short top-level tasks are present in + * a small number of queues, the above signalling strategy may + * activate many more workers than needed, worsening locality and + * contention problems, while also generating more global + * contention (field ctl is CASed on every activation and + * deactivation). We filter out (both in runWorker and + * signalWork) attempted signals that are surely not needed + * because the signalled tasks are already taken. + * + * Shutdown and Quiescence + * ======================= * * Quiescence. Workers scan looking for work, giving up when they * don't find any, without being sure that none are available. @@ -892,9 +873,7 @@ public class ForkJoinPool extends AbstractExecutorService * shutdown, runners are interrupted so they can cancel. Since * external joining callers never run these tasks, they must await * cancellation by others, which can occur along several different - * paths. The inability to rely on caller-runs may also require - * extra signalling (resulting in scanning and contention) so is - * done only conditionally in methods push and runworker. + * paths. * * Across these APIs, rules for reporting exceptions for tasks * with results accessed via join() differ from those via get(), @@ -961,9 +940,13 @@ public class ForkJoinPool extends AbstractExecutorService * less-contended applications. To help arrange this, some * non-reference fields are declared as "long" even when ints or * shorts would suffice. For class WorkQueue, an - * embedded @Contended region segregates fields most heavily - * updated by owners from those most commonly read by stealers or - * other management. + * embedded @Contended isolates the very busy top index, along + * with status and bookkeeping fields written (mostly) by owners, + * that otherwise interfere with reading array and base + * fields. There are other variables commonly contributing to + * false-sharing-related performance issues (including fields of + * class Thread), but we can't do much about this except try to + * minimize access. * * Initial sizing and resizing of WorkQueue arrays is an even more * delicate tradeoff because the best strategy systematically @@ -972,13 +955,11 @@ public class ForkJoinPool extends AbstractExecutorService * direct false-sharing and indirect cases due to GC bookkeeping * (cardmarks etc), and reduce the number of resizes, which are * not especially fast because they require atomic transfers. - * Currently, arrays for workers are initialized to be just large - * enough to avoid resizing in most tree-structured tasks, but - * larger for external queues where both false-sharing problems - * and the need for resizing are more common. (Maintenance note: - * any changes in fields, queues, or their uses, or JVM layout - * policies, must be accompanied by re-evaluation of these - * placement and sizing decisions.) + * Currently, arrays are initialized to be just large enough to + * avoid resizing in most tree-structured tasks, but grow rapidly + * until large. (Maintenance note: any changes in fields, queues, + * or their uses, or JVM layout policies, must be accompanied by + * re-evaluation of these placement and sizing decisions.) * * Style notes * =========== @@ -1061,17 +1042,11 @@ public class ForkJoinPool extends AbstractExecutorService static final int DEFAULT_COMMON_MAX_SPARES = 256; /** - * Initial capacity of work-stealing queue array for workers. + * Initial capacity of work-stealing queue array. * Must be a power of two, at least 2. See above. */ static final int INITIAL_QUEUE_CAPACITY = 1 << 6; - /** - * Initial capacity of work-stealing queue array for external queues. - * Must be a power of two, at least 2. See above. - */ - static final int INITIAL_EXTERNAL_QUEUE_CAPACITY = 1 << 9; - // conversions among short, int, long static final int SMASK = 0xffff; // (unsigned) short bits static final long LMASK = 0xffffffffL; // lower 32 bits of long @@ -1211,11 +1186,11 @@ public class ForkJoinPool extends AbstractExecutorService @jdk.internal.vm.annotation.Contended("w") int stackPred; // pool stack (ctl) predecessor link @jdk.internal.vm.annotation.Contended("w") + volatile int parking; // nonzero if parked in awaitWork + @jdk.internal.vm.annotation.Contended("w") volatile int source; // source queue id (or DROPPED) @jdk.internal.vm.annotation.Contended("w") int nsteals; // number of steals from other queues - @jdk.internal.vm.annotation.Contended("w") - volatile int parking; // nonzero if parked in awaitWork // Support for atomic operations private static final Unsafe U; @@ -1248,11 +1223,11 @@ public class ForkJoinPool extends AbstractExecutorService */ WorkQueue(ForkJoinWorkerThread owner, int id, int cfg, boolean clearThreadLocals) { - array = new ForkJoinTask[owner == null ? - INITIAL_EXTERNAL_QUEUE_CAPACITY : - INITIAL_QUEUE_CAPACITY]; - this.owner = owner; this.config = (clearThreadLocals) ? cfg | CLEAR_TLS : cfg; + if ((this.owner = owner) == null) { + array = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; + phase = id | IDLE; + } } /** @@ -1279,27 +1254,27 @@ public class ForkJoinPool extends AbstractExecutorService * @throws RejectedExecutionException if array could not be resized */ final void push(ForkJoinTask task, ForkJoinPool pool, boolean internal) { - int s = top, b = base, m, cap, room; ForkJoinTask[] a; - if ((a = array) != null && (cap = a.length) > 0 && // else disabled - task != null) { - int pk = task.noUserHelp() + 1; // prev slot offset - if ((room = (m = cap - 1) - (s - b)) >= 0) { + int s = top, b = base, m, cap, room; ForkJoinTask[] a, na; + if ((a = array) != null && (cap = a.length) > 0) { // else disabled + int k = (m = cap - 1) & s; + if ((room = m - (s - b)) >= 0) { top = s + 1; - long pos = slotOffset(m & s); + long pos = slotOffset(k); if (!internal) U.putReference(a, pos, task); // inside lock else U.getAndSetReference(a, pos, task); // fully fenced - if (room == 0) // resize - growArray(a, cap, s); + if (room == 0 && (na = growArray(a, cap, s)) != null) + k = ((a = na).length - 1) & s; // resize } if (!internal) unlockPhase(); if (room < 0) throw new RejectedExecutionException("Queue capacity exceeded"); - if ((room == 0 || a[m & (s - pk)] == null) && - pool != null) - pool.signalWork(); // may have appeared empty + if (pool != null && + (room == 0 || + U.getReferenceAcquire(a, slotOffset(m & (s - 1))) == null)) + pool.signalWork(a, k); // may have appeared empty } } @@ -1308,11 +1283,12 @@ public class ForkJoinPool extends AbstractExecutorService * @param a old array * @param cap old array capacity * @param s current top + * @return new array, or null on failure */ - private void growArray(ForkJoinTask[] a, int cap, int s) { - int newCap = cap << 1; + private ForkJoinTask[] growArray(ForkJoinTask[] a, int cap, int s) { + int newCap = (cap >= 1 << 16) ? cap << 1 : cap << 2; + ForkJoinTask[] newArray = null; if (a != null && a.length == cap && cap > 0 && newCap > 0) { - ForkJoinTask[] newArray = null; try { newArray = new ForkJoinTask[newCap]; } catch (OutOfMemoryError ex) { @@ -1329,34 +1305,45 @@ public class ForkJoinPool extends AbstractExecutorService updateArray(newArray); // fully fenced } } + return newArray; } /** - * Takes next task, if one exists, in order specified by mode, - * so acts as either local-pop or local-poll. Called only by owner. - * @param fifo nonzero if FIFO mode + * Takes next task, if one exists, in lifo order. */ - private ForkJoinTask nextLocalTask(int fifo) { + private ForkJoinTask localPop() { ForkJoinTask t = null; - ForkJoinTask[] a = array; - int b = base, p = top, cap; - if (p - b > 0 && a != null && (cap = a.length) > 0) { - for (int m = cap - 1, s, nb;;) { - if (fifo == 0 || (nb = b + 1) == p) { - if ((t = (ForkJoinTask)U.getAndSetReference( - a, slotOffset(m & (s = p - 1)), null)) != null) - updateTop(s); // else lost race for only task - break; + int s = top - 1, cap; long k; ForkJoinTask[] a; + if ((a = array) != null && (cap = a.length) > 0 && + U.getReference(a, k = slotOffset((cap - 1) & s)) != null && + (t = (ForkJoinTask)U.getAndSetReference(a, k, null)) != null) + updateTop(s); + return t; + } + + /** + * Takes next task, if one exists, in fifo order. + */ + private ForkJoinTask localPoll() { + ForkJoinTask t = null; + int p = top, cap; ForkJoinTask[] a; + if ((a = array) != null && (cap = a.length) > 0) { + for (int b = base; p - b > 0; ) { + int nb = b + 1; + long k = slotOffset((cap - 1) & b); + if (U.getReference(a, k) == null) { + if (nb == p) + break; // else base is lagging + while (b == (b = U.getIntAcquire(this, BASE))) + Thread.onSpinWait(); // spin to reduce memory traffic } - if ((t = (ForkJoinTask)U.getAndSetReference( - a, slotOffset(m & b), null)) != null) { + else if ((t = (ForkJoinTask) + U.getAndSetReference(a, k, null)) != null) { updateBase(nb); break; } - while (b == (b = U.getIntAcquire(this, BASE))) - Thread.onSpinWait(); // spin to reduce memory traffic - if (p - b <= 0) - break; + else + b = base; } } return t; @@ -1364,10 +1351,9 @@ public class ForkJoinPool extends AbstractExecutorService /** * Takes next task, if one exists, using configured mode. - * (Always internal, never called for Common pool.) */ final ForkJoinTask nextLocalTask() { - return nextLocalTask(config & FIFO); + return (config & FIFO) == 0 ? localPop() : localPoll(); } /** @@ -1443,12 +1429,12 @@ public class ForkJoinPool extends AbstractExecutorService // specialized execution methods /** - * Runs the given task, as well as remaining local tasks. + * Runs the given task, as well as remaining local tasks */ final void topLevelExec(ForkJoinTask task, int fifo) { while (task != null) { task.doExec(); - task = nextLocalTask(fifo); + task = (fifo != 0) ? localPoll() : localPop(); } } @@ -1578,7 +1564,7 @@ public class ForkJoinPool extends AbstractExecutorService * Cancels all local tasks. Called only by owner. */ final void cancelTasks() { - for (ForkJoinTask t; (t = nextLocalTask(0)) != null; ) { + for (ForkJoinTask t; (t = localPop()) != null; ) { try { t.cancel(false); } catch (Throwable ignore) { @@ -1780,7 +1766,8 @@ public class ForkJoinPool extends AbstractExecutorService * @param w caller's WorkQueue */ final void registerWorker(WorkQueue w) { - if (w != null && (runState & STOP) == 0L) { + if (w != null) { + w.array = new ForkJoinTask[INITIAL_QUEUE_CAPACITY]; ThreadLocalRandom.localInit(); int seed = w.stackPred = ThreadLocalRandom.getProbe(); int phaseSeq = seed & ~((IDLE << 1) - 1); // initial phase tag @@ -1858,17 +1845,18 @@ public class ForkJoinPool extends AbstractExecutorService } if ((tryTerminate(false, false) & STOP) == 0L && phase != 0 && w != null && w.source != DROPPED) { - signalWork(); // possibly replace w.cancelTasks(); // clean queue + signalWork(null, 0); // possibly replace } if (ex != null) ForkJoinTask.rethrow(ex); } /** - * Releases an idle worker, or creates one if not enough exist. + * Releases an idle worker, or creates one if not enough exist, + * giving up if array a is nonnull and task at a[k] already taken. */ - final void signalWork() { + final void signalWork(ForkJoinTask[] a, int k) { int pc = parallelism; for (long c = ctl;;) { WorkQueue[] qs = queues; @@ -1884,13 +1872,15 @@ public class ForkJoinPool extends AbstractExecutorService if (sp == 0) { if ((short)(c >>> TC_SHIFT) >= pc) break; - nc = ((c + TC_UNIT) & TC_MASK); + nc = ((c + TC_UNIT) & TC_MASK) | ac; } else if ((v = w) == null) break; else - nc = (v.stackPred & LMASK) | (c & TC_MASK); - if (c == (c = compareAndExchangeCtl(c, nc | ac))) { + nc = (v.stackPred & LMASK) | (c & TC_MASK) | ac; + if (a != null && k < a.length && k >= 0 && a[k] == null) + break; + if (c == (c = ctl) && c == (c = compareAndExchangeCtl(c, nc))) { if (v == null) createWorker(); else { @@ -1973,178 +1963,196 @@ public class ForkJoinPool extends AbstractExecutorService * @param w caller's WorkQueue (may be null on failed initialization) */ final void runWorker(WorkQueue w) { - if (w != null) { - int phase = w.phase, r = w.stackPred; // seed from registerWorker - int fifo = w.config & FIFO, nsteals = 0, src = -1; - for (;;) { - WorkQueue[] qs; + if (w != null && w.phase != 0) { // else unregistered + WorkQueue[] qs; + int r = w.stackPred; // seed from registerWorker + int fifo = (int)config & FIFO, rescans = 0, inactive = 0, taken = 0, n; + while ((runState & STOP) == 0L && (qs = queues) != null && + (n = qs.length) > 0) { + int i = r, step = (r >>> 16) | 1; r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift - if ((runState & STOP) != 0L || (qs = queues) == null) - break; - int n = qs.length, i = r, step = (r >>> 16) | 1; - boolean rescan = false; - scan: for (int l = n; l > 0; --l, i += step) { // scan queues - int j, cap; WorkQueue q; ForkJoinTask[] a; - if ((q = qs[j = i & (n - 1)]) != null && - (a = q.array) != null && (cap = a.length) > 0) { - for (int m = cap - 1, pb = -1, b = q.base;;) { - ForkJoinTask t; long k; + scan: for (int j = n; j != 0; --j, i += step) { + WorkQueue q; int qid; + if ((q = qs[qid = i & (n - 1)]) != null) { + ForkJoinTask[] a; int cap; // poll queue + while ((a = q.array) != null && (cap = a.length) > 0) { + int b, nb, nk; long bp; ForkJoinTask t; t = (ForkJoinTask)U.getReferenceAcquire( - a, k = slotOffset(m & b)); - if (b != (b = q.base) || t == null || - !U.compareAndSetReference(a, k, t, null)) { - if (a[b & m] == null) { - if (rescan) // end of run - break scan; - if (a[(b + 1) & m] == null && - a[(b + 2) & m] == null) { - break; // probably empty + a, bp = slotOffset((cap - 1) & (b = q.base))); + long np = slotOffset(nk = (nb = b + 1) & (cap - 1)); + if (q.base == b) { // else inconsistent + if (t == null) { + if (q.array == a) { // else resized + if (rescans > 0) // ran or stalled + break scan; + if (U.getReference(a, np) == null && + (rescans >= 0 || + (U.getReferenceAcquire(a, bp) == null && + q.top == q.base))) + break; + rescans = 1; // may be stalled } - if (pb == (pb = b)) { // track progress - rescan = true; // stalled; reorder scan + } + else if (inactive != 0) { + if ((inactive = tryReactivate(w)) != 0) { + rescans = 1; // can't take yet break scan; } } - } - else { - boolean propagate; - int nb = q.base = b + 1, prevSrc = src; - w.nsteals = ++nsteals; - w.source = src = j; // volatile - rescan = true; - int nh = t.noUserHelp(); - if (propagate = - (prevSrc != src || nh != 0) && a[nb & m] != null) - signalWork(); - w.topLevelExec(t, fifo); - if ((b = q.base) != nb && !propagate) - break scan; // reduce interference + else if (U.compareAndSetReference(a, bp, t, null)) { + q.base = nb; + Object nt = U.getReferenceAcquire(a, np); + w.source = qid; + rescans = 1; + ++taken; + if (nt != null && // confirm a[nk] + U.getReferenceAcquire(a, np) == nt) + signalWork(a, nk); // propagate + w.topLevelExec(t, fifo); + } } } } } - if (!rescan) { - if (((phase = deactivate(w, phase)) & IDLE) != 0) - break; - src = -1; // re-enable propagation + if (rescans >= 0) + --rescans; + else if (inactive == 0) { + if ((inactive = deactivate(w, taken)) != 0) + taken = 0; } + else if (awaitWork(w) == 0) + inactive = rescans = 0; + else + break; } } } /** - * Deactivates and if necessary awaits signal or termination. + * Tries to deactivate worker, keeping active on contention * - * @param w the worker - * @param phase current phase - * @return current phase, with IDLE set if worker should exit + * @param w the work queue + * @param taken number of stolen tasks since last deactivation + * @return nonzero if inactive */ - private int deactivate(WorkQueue w, int phase) { - if (w == null) // currently impossible - return IDLE; - int p = phase | IDLE, activePhase = phase + (IDLE << 1); - long pc = ctl, qc = (activePhase & LMASK) | ((pc - RC_UNIT) & UMASK); - int sp = w.stackPred = (int)pc; // set ctl stack link - w.phase = p; - if (!compareAndSetCtl(pc, qc)) // try to enqueue - return w.phase = phase; // back out on possible signal - int ac = (short)(qc >>> RC_SHIFT), n; long e; WorkQueue[] qs; - if (((e = runState) & STOP) != 0L || - ((e & SHUTDOWN) != 0L && ac == 0 && quiescent() > 0) || - (qs = queues) == null || (n = qs.length) <= 0) - return IDLE; // terminating - - for (int prechecks = Math.min(ac, 2), // reactivation threshold - k = Math.max(n + (n << 1), SPIN_WAITS << 1);;) { - WorkQueue q; int cap; ForkJoinTask[] a; long c; - if (w.phase == activePhase) - return activePhase; - if (--k < 0) - return awaitWork(w, p); // block, drop, or exit - if ((q = qs[k & (n - 1)]) == null) - Thread.onSpinWait(); - else if ((a = q.array) != null && (cap = a.length) > 0 && - a[q.base & (cap - 1)] != null && --prechecks < 0 && - (int)(c = ctl) == activePhase && - compareAndSetCtl(c, (sp & LMASK) | ((c + RC_UNIT) & UMASK))) - return w.phase = activePhase; // reactivate + private int deactivate(WorkQueue w, int taken) { + int inactive = 0, phase; + if (w != null && (inactive = (phase = w.phase) & IDLE) == 0) { + long sp = (phase + (IDLE << 1)) & LMASK, pc, c; + w.phase = phase | IDLE; + w.stackPred = (int)(pc = ctl); // set ctl stack link + if (!compareAndSetCtl( // try to enqueue + pc, c = ((pc - RC_UNIT) & UMASK) | sp)) + w.phase = phase; // back out on contention + else { + if (taken != 0) { + w.nsteals += taken; + if ((w.config & CLEAR_TLS) != 0 && + (Thread.currentThread() instanceof ForkJoinWorkerThread f)) + f.resetThreadLocals(); // (instanceof check always true) + } + if (((c & RC_MASK) == 0L && quiescent() > 0) || taken == 0) + inactive = w.phase & IDLE; // check quiescent termination + else { // spin for approx 1 scan cost + int tc = (short)(c >>> TC_SHIFT); + int spins = Math.max((tc << 1) + tc, SPIN_WAITS); + while ((inactive = w.phase & IDLE) != 0 && --spins != 0) + Thread.onSpinWait(); + } + } } + return inactive; + } + + /** + * Reactivates worker w if it is currently top of ctl stack + * + * @param w the work queue + * @return 0 if now active + */ + private int tryReactivate(WorkQueue w) { + int inactive = 0; + if (w != null) { // always true; hoist checks + int sp = w.stackPred, phase, activePhase; long c; + if ((inactive = (phase = w.phase) & IDLE) != 0 && + (int)(c = ctl) == (activePhase = phase + IDLE) && + compareAndSetCtl(c, (sp & LMASK) | ((c + RC_UNIT) & UMASK))) { + w.phase = activePhase; + inactive = 0; + } + } + return inactive; } /** * Awaits signal or termination. * * @param w the work queue - * @param p current phase (known to be idle) - * @return current phase, with IDLE set if worker should exit + * @return 0 if now active */ - private int awaitWork(WorkQueue w, int p) { - if (w != null) { - ForkJoinWorkerThread t; long deadline; - if ((w.config & CLEAR_TLS) != 0 && (t = w.owner) != null) - t.resetThreadLocals(); // clear before reactivate - if ((ctl & RC_MASK) > 0L) - deadline = 0L; - else if ((deadline = - (((w.source != INVALID_ID) ? keepAlive : TIMEOUT_SLOP)) + - System.currentTimeMillis()) == 0L) - deadline = 1L; // avoid zero - int activePhase = p + IDLE; - if ((p = w.phase) != activePhase && (runState & STOP) == 0L) { + private int awaitWork(WorkQueue w) { + int inactive = 0, phase; + if (w != null) { // always true; hoist checks + long waitTime = (w.source == INVALID_ID) ? 0L : keepAlive; + if ((inactive = (phase = w.phase) & IDLE) != 0) { LockSupport.setCurrentBlocker(this); - w.parking = 1; // enable unpark - while ((p = w.phase) != activePhase) { - boolean trimmable = false; int trim; - Thread.interrupted(); // clear status + int activePhase = phase + IDLE; + for (long deadline = 0L;;) { + Thread.interrupted(); // clear status if ((runState & STOP) != 0L) break; - if (deadline != 0L) { - if ((trim = tryTrim(w, p, deadline)) > 0) - break; - else if (trim < 0) - deadline = 0L; - else - trimmable = true; + boolean trimmable = false; // use timed wait if trimmable + long d = 0L, c; + if (((c = ctl) & RC_MASK) == 0L && (int)c == activePhase) { + long now = System.currentTimeMillis(); + if (deadline == 0L) + deadline = waitTime + now; + if (deadline - now <= TIMEOUT_SLOP) { + if (tryTrim(w, c, activePhase)) + break; + continue; // lost race to trim + } + d = deadline; + trimmable = true; } - U.park(trimmable, deadline); + w.parking = 1; // enable unpark and recheck + if ((inactive = w.phase & IDLE) != 0) + U.park(trimmable, d); + w.parking = 0; // close unpark window + if (inactive == 0 || (inactive = w.phase & IDLE) == 0) + break; } - w.parking = 0; LockSupport.setCurrentBlocker(null); } } - return p; + return inactive; } /** * Tries to remove and deregister worker after timeout, and release - * another to do the same. - * @return > 0: trimmed, < 0 : not trimmable, else 0 + * another to do the same unless new tasks are found. */ - private int tryTrim(WorkQueue w, int phase, long deadline) { - long c, nc; int stat, activePhase, vp, i; WorkQueue[] vs; WorkQueue v; - if ((activePhase = phase + IDLE) != (int)(c = ctl) || w == null) - stat = -1; // no longer ctl top - else if (deadline - System.currentTimeMillis() >= TIMEOUT_SLOP) - stat = 0; // spurious wakeup - else if (!compareAndSetCtl( - c, nc = ((w.stackPred & LMASK) | (RC_MASK & c) | - (TC_MASK & (c - TC_UNIT))))) - stat = -1; // lost race to signaller - else { - stat = 1; - w.source = DROPPED; - w.phase = activePhase; - if ((vp = (int)nc) != 0 && (vs = queues) != null && - vs.length > (i = vp & SMASK) && (v = vs[i]) != null && - compareAndSetCtl( // try to wake up next waiter - nc, ((UMASK & (nc + RC_UNIT)) | - (nc & TC_MASK) | (v.stackPred & LMASK)))) { - v.source = INVALID_ID; // enable cascaded timeouts - v.phase = vp; - U.unpark(v.owner); + private boolean tryTrim(WorkQueue w, long c, int activePhase) { + if (w != null) { + int vp, i; WorkQueue[] vs; WorkQueue v; + long nc = ((w.stackPred & LMASK) | + ((RC_MASK & c) | (TC_MASK & (c - TC_UNIT)))); + if (compareAndSetCtl(c, nc)) { + w.source = DROPPED; + w.phase = activePhase; + if ((vp = (int)nc) != 0 && (vs = queues) != null && + vs.length > (i = vp & SMASK) && (v = vs[i]) != null && + compareAndSetCtl( // try to wake up next waiter + nc, ((v.stackPred & LMASK) | + ((UMASK & (nc + RC_UNIT)) | (nc & TC_MASK))))) { + v.source = INVALID_ID; // enable cascaded timeouts + v.phase = vp; + U.unpark(v.owner); + } + return true; } } - return stat; + return false; } /** @@ -2561,52 +2569,35 @@ public class ForkJoinPool extends AbstractExecutorService /** * Finds and locks a WorkQueue for an external submitter, or - * throws RejectedExecutionException if shutdown or terminating. - * @param r current ThreadLocalRandom.getProbe() value + * throws RejectedExecutionException if shutdown * @param rejectOnShutdown true if RejectedExecutionException - * should be thrown when shutdown (else only if terminating) + * should be thrown when shutdown */ - private WorkQueue submissionQueue(int r, boolean rejectOnShutdown) { - int reuse; // nonzero if prefer create - if ((reuse = r) == 0) { - ThreadLocalRandom.localInit(); // initialize caller's probe + final WorkQueue externalSubmissionQueue(boolean rejectOnShutdown) { + int r; + if ((r = ThreadLocalRandom.getProbe()) == 0) { + ThreadLocalRandom.localInit(); // initialize caller's probe r = ThreadLocalRandom.getProbe(); } - for (int probes = 0; ; ++probes) { - int n, i, id; WorkQueue[] qs; WorkQueue q; - if ((qs = queues) == null) - break; - if ((n = qs.length) <= 0) + for (;;) { + WorkQueue q; WorkQueue[] qs; int n, id, i; + if ((qs = queues) == null || (n = qs.length) <= 0) break; if ((q = qs[i = (id = r & EXTERNAL_ID_MASK) & (n - 1)]) == null) { - WorkQueue w = new WorkQueue(null, id, 0, false); - w.phase = id; - boolean reject = ((lockRunState() & SHUTDOWN) != 0 && - rejectOnShutdown); - if (!reject && queues == qs && qs[i] == null) - q = qs[i] = w; // else lost race to install + WorkQueue newq = new WorkQueue(null, id, 0, false); + lockRunState(); + if (qs[i] == null && queues == qs) + q = qs[i] = newq; // else lost race to install unlockRunState(); - if (q != null) - return q; - if (reject) + } + if (q != null && q.tryLockPhase()) { + if (rejectOnShutdown && (runState & SHUTDOWN) != 0L) { + q.unlockPhase(); // check while q lock held break; - reuse = 0; - } - if (reuse == 0 || !q.tryLockPhase()) { // move index - if (reuse == 0) { - if (probes >= n >> 1) - reuse = r; // stop prefering free slot } - else if (q != null) - reuse = 0; // probe on collision - r = ThreadLocalRandom.advanceProbe(r); - } - else if (rejectOnShutdown && (runState & SHUTDOWN) != 0L) { - q.unlockPhase(); // check while q lock held - break; - } - else return q; + } + r = ThreadLocalRandom.advanceProbe(r); // move } throw new RejectedExecutionException(); } @@ -2620,24 +2611,12 @@ public class ForkJoinPool extends AbstractExecutorService } else { // find and lock queue internal = false; - q = submissionQueue(ThreadLocalRandom.getProbe(), true); + q = externalSubmissionQueue(true); } q.push(task, signalIfEmpty ? this : null, internal); return task; } - /** - * Returns queue for an external submission, bypassing call to - * submissionQueue if already established and unlocked. - */ - final WorkQueue externalSubmissionQueue(boolean rejectOnShutdown) { - WorkQueue[] qs; WorkQueue q; int n; - int r = ThreadLocalRandom.getProbe(); - return (((qs = queues) != null && (n = qs.length) > 0 && - (q = qs[r & EXTERNAL_ID_MASK & (n - 1)]) != null && r != 0 && - q.tryLockPhase()) ? q : submissionQueue(r, rejectOnShutdown)); - } - /** * Returns queue for an external thread, if one exists that has * possibly ever submitted to the given pool (nonzero probe), or @@ -3310,11 +3289,14 @@ public class ForkJoinPool extends AbstractExecutorService * @since 19 */ public int setParallelism(int size) { + int prevSize; if (size < 1 || size > MAX_CAP) throw new IllegalArgumentException(); if ((config & PRESET_SIZE) != 0) throw new UnsupportedOperationException("Cannot override System property"); - return getAndSetParallelism(size); + if ((prevSize = getAndSetParallelism(size)) < size) + signalWork(null, 0); // trigger worker activation + return prevSize; } /** diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java index 118d648c7a2..787d8d5fecd 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java @@ -588,13 +588,15 @@ public class LinkedTransferQueue extends AbstractQueue do { m = p.item; q = p.next; - if (p.isData != haveData && haveData != (m != null) && - p.cmpExItem(m, e) == m) { - Thread w = p.waiter; // matched complementary node - if (p != h && h == cmpExHead(h, (q == null) ? p : q)) - h.next = h; // advance head; self-link old - LockSupport.unpark(w); - return m; + if (p.isData != haveData && haveData != (m != null)) { + if (p.cmpExItem(m, e) == m) { + Thread w = p.waiter; // matched complementary node + if (p != h && h == cmpExHead(h, (q == null) ? p : q)) + h.next = h; // advance head; self-link old + LockSupport.unpark(w); + return m; + } + continue restart; } else if (q == null) { if (ns == 0L) // try to append unless immediate break restart; diff --git a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java index 941d6bd55cb..01bf1158bf6 100644 --- a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java +++ b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java @@ -914,8 +914,8 @@ public sealed interface StructuredTaskScope * forking subtasks will create an unnamed virtual thread for each subtask. * *

    If a {@linkplain Configuration#withTimeout(Duration) timeout} is set then it - * starts when the scope is opened. If the timeout expires before the scope has - * {@linkplain #join() joined} then the scope is {@linkplain ##Cancellation cancelled} + * starts when the scope is opened. If the timeout expires before or while waiting in + * {@link #join()} then the scope is {@linkplain ##Cancellation cancelled} * and the {@code Joiner}'s {@link Joiner#onTimeout() onTimeout()} method is invoked * to optionally throw {@link TimeoutException TimeoutException}. * diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java index 3713d616a3a..deed7f018c3 100644 --- a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java +++ b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java @@ -128,11 +128,6 @@ public final class ThreadLocalRandom extends Random { * Implementations of non-core methods are mostly the same as in * SplittableRandom, that were in part derived from a previous * version of this class. - * - * This implementation of ThreadLocalRandom overrides the - * definition of the nextGaussian() method in the class Random, - * and instead uses the ziggurat-based algorithm that is the - * default for the RandomGenerator interface. */ private static int mix32(long z) { @@ -499,6 +494,23 @@ public final class ThreadLocalRandom extends Random { return super.nextLong(origin, bound); } + /** + * Returns a {@code double} value pseudorandomly chosen from a Gaussian + * (normal) distribution whose mean is 0 and whose standard deviation is 1. + * + * @return a {@code double} value pseudorandomly chosen from a + * Gaussian distribution + * + * @implNote This implementation invokes the default implementation of + * {@link java.util.random.RandomGenerator#nextGaussian()}, + * and so it uses McFarland's fast modified ziggurat algorithm + * rather than the polar method described in the superclass. + */ + @Override + public double nextGaussian() { + return RandomSupport.computeNextGaussian(this); + } + /** * {@inheritDoc} */ @@ -510,7 +522,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} * * @since 17 */ @@ -522,7 +533,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} * * @since 17 */ @@ -542,7 +552,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} */ @Override public double nextDouble(double bound) { @@ -552,7 +561,6 @@ public final class ThreadLocalRandom extends Random { /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @implNote {@inheritDoc} */ @Override public double nextDouble(double origin, double bound) { diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java index 029e31ef9f6..b45b6eac83e 100644 --- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java +++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java @@ -1426,23 +1426,6 @@ public class ThreadPoolExecutor extends AbstractExecutorService { } } - // Override without "throws Throwable" for compatibility with subclasses - // whose finalize method invokes super.finalize() (as is recommended). - // Before JDK 11, finalize() had a non-empty method body. - - /** - * @implNote Previous versions of this class had a finalize method - * that shut down this executor, but in this version, finalize - * does nothing. - * - * @deprecated Finalization has been deprecated for removal. See - * {@link java.lang.Object#finalize} for background information and details - * about migration options. - */ - @Deprecated(since="9", forRemoval=true) - @SuppressWarnings("removal") - protected void finalize() {} - /** * Sets the thread factory used to create new threads. * diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index dc2d65bcc99..d1a8f1310a9 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -27,7 +27,6 @@ package java.util.jar; import jdk.internal.access.SharedSecrets; import jdk.internal.access.JavaUtilZipFileAccess; -import jdk.internal.misc.ThreadTracker; import sun.security.util.ManifestEntryVerifier; import sun.security.util.SignatureFileVerifier; @@ -213,6 +212,9 @@ public class JarFile extends ZipFile { */ static final String INDEX_NAME = "META-INF/INDEX.LIST"; + // this will be set when the thread is initializing a JAR verifier + private static final ScopedValue IN_VERIFIER_INIT = ScopedValue.newInstance(); + /** * Returns the version that represents the unversioned configuration of a * multi-release jar file. @@ -1025,36 +1027,30 @@ public class JarFile extends ZipFile { } } - private static class ThreadTrackHolder { - static final ThreadTracker TRACKER = new ThreadTracker(); - } - - private static Object beginInit() { - return ThreadTrackHolder.TRACKER.begin(); - } - - private static void endInit(Object key) { - ThreadTrackHolder.TRACKER.end(key); - } - synchronized void ensureInitialization() { try { maybeInstantiateVerifier(); } catch (IOException e) { throw new RuntimeException(e); } - if (jv != null && !jvInitialized) { - Object key = beginInit(); - try { + if (jv == null || jvInitialized) { + return; + } + // mark the current thread as initializing + // the JAR verifier + ScopedValue.where(IN_VERIFIER_INIT, true).run(new Runnable() { + @Override + public void run() { initializeVerifier(); jvInitialized = true; - } finally { - endInit(key); } - } + }); } + /** + * {@return true if the current thread is initializing a JAR verifier, false otherwise} + */ static boolean isInitializing() { - return ThreadTrackHolder.TRACKER.contains(Thread.currentThread()); + return IN_VERIFIER_INIT.isBound(); } } diff --git a/src/java.base/share/classes/java/util/random/RandomGenerator.java b/src/java.base/share/classes/java/util/random/RandomGenerator.java index e019e073a2d..2195774e591 100644 --- a/src/java.base/share/classes/java/util/random/RandomGenerator.java +++ b/src/java.base/share/classes/java/util/random/RandomGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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 @@ -917,7 +917,6 @@ public interface RandomGenerator { * a discrete distribution also plays a role. */ default double nextGaussian() { - // See Knuth, TAOCP, Vol. 2, 3rd edition, Section 3.4.1 Algorithm C. return RandomSupport.computeNextGaussian(this); } diff --git a/src/java.base/share/classes/java/util/regex/Pattern.java b/src/java.base/share/classes/java/util/regex/Pattern.java index 2908370acd5..58c9186924b 100644 --- a/src/java.base/share/classes/java/util/regex/Pattern.java +++ b/src/java.base/share/classes/java/util/regex/Pattern.java @@ -43,8 +43,8 @@ import java.util.function.Predicate; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.internal.lang.CaseFolding; import jdk.internal.util.ArraysSupport; -import jdk.internal.util.regex.CaseFolding; import jdk.internal.util.regex.Grapheme; /** diff --git a/src/java.base/share/classes/java/util/stream/SortedOps.java b/src/java.base/share/classes/java/util/stream/SortedOps.java index 91892eba44f..1286735ebd9 100644 --- a/src/java.base/share/classes/java/util/stream/SortedOps.java +++ b/src/java.base/share/classes/java/util/stream/SortedOps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -108,13 +108,10 @@ final class SortedOps { * {@code Comparable}. */ OfRef(AbstractPipeline upstream) { - super(upstream, StreamShape.REFERENCE, - StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED); - this.isNaturalSort = true; // Will throw CCE when we try to sort if T is not Comparable @SuppressWarnings("unchecked") Comparator comp = (Comparator) Comparator.naturalOrder(); - this.comparator = comp; + this(upstream, comp); } /** @@ -123,10 +120,13 @@ final class SortedOps { * @param comparator The comparator to be used to evaluate ordering. */ OfRef(AbstractPipeline upstream, Comparator comparator) { + Objects.requireNonNull(comparator); + boolean isNaturalSort = Comparator.naturalOrder().equals(comparator); + this.comparator = comparator; + this.isNaturalSort = isNaturalSort; super(upstream, StreamShape.REFERENCE, - StreamOpFlag.IS_ORDERED | StreamOpFlag.NOT_SORTED); - this.isNaturalSort = false; - this.comparator = Objects.requireNonNull(comparator); + StreamOpFlag.IS_ORDERED | + (isNaturalSort ? StreamOpFlag.IS_SORTED : StreamOpFlag.NOT_SORTED)); } @Override diff --git a/src/java.base/share/classes/java/util/stream/StreamOpFlag.java b/src/java.base/share/classes/java/util/stream/StreamOpFlag.java index df98125cbc0..0e7b2f6607b 100644 --- a/src/java.base/share/classes/java/util/stream/StreamOpFlag.java +++ b/src/java.base/share/classes/java/util/stream/StreamOpFlag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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,6 +24,7 @@ */ package java.util.stream; +import java.util.Comparator; import java.util.EnumMap; import java.util.Map; import java.util.Spliterator; @@ -738,9 +739,9 @@ enum StreamOpFlag { * * @implSpec * If the spliterator is naturally {@code SORTED} (the associated - * {@code Comparator} is {@code null}) then the characteristic is converted - * to the {@link #SORTED} flag, otherwise the characteristic is not - * converted. + * {@code Comparator} is {@code null} or {@code Comparator.naturalOrder()}) then + * the characteristic is converted to the {@link #SORTED} flag, otherwise + * the characteristic is not converted. * * @param spliterator the spliterator from which to obtain characteristic * bit set. @@ -748,14 +749,15 @@ enum StreamOpFlag { */ static int fromCharacteristics(Spliterator spliterator) { int characteristics = spliterator.characteristics(); - if ((characteristics & Spliterator.SORTED) != 0 && spliterator.getComparator() != null) { - // Do not propagate the SORTED characteristic if it does not correspond - // to a natural sort order - return characteristics & SPLITERATOR_CHARACTERISTICS_MASK & ~Spliterator.SORTED; - } - else { - return characteristics & SPLITERATOR_CHARACTERISTICS_MASK; + if ((characteristics & Spliterator.SORTED) != 0) { + Comparator comparator = spliterator.getComparator(); + if (comparator != null && !Comparator.naturalOrder().equals(comparator)) { + // Do not propagate the SORTED characteristic if it does not correspond + // to a natural sort order + return characteristics & SPLITERATOR_CHARACTERISTICS_MASK & ~Spliterator.SORTED; + } } + return characteristics & SPLITERATOR_CHARACTERISTICS_MASK; } /** diff --git a/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java b/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java index 90316d7437e..dc3c4c14b27 100644 --- a/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java +++ b/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java @@ -276,8 +276,7 @@ public non-sealed class EncryptedPrivateKeyInfo implements DEREncodable { * @param cipher the initialized {@code Cipher} object which will be * used for decrypting the encrypted data. * @return the PKCS8EncodedKeySpec object. - * @exception NullPointerException if {@code cipher} - * is {@code null}. + * @exception NullPointerException if {@code cipher} is {@code null}. * @exception InvalidKeySpecException if the given cipher is * inappropriate for the encrypted data or the encrypted * data is corrupted and cannot be decrypted. @@ -296,10 +295,9 @@ public non-sealed class EncryptedPrivateKeyInfo implements DEREncodable { } } - private PKCS8EncodedKeySpec getKeySpecImpl(Key decryptKey, - Provider provider) throws NoSuchAlgorithmException, - InvalidKeyException { - byte[] encoded; + // Return the decrypted encryptedData in this instance. + private byte[] decryptData(Key decryptKey, Provider provider) + throws NoSuchAlgorithmException, InvalidKeyException { Cipher c; try { if (provider == null) { @@ -308,162 +306,157 @@ public non-sealed class EncryptedPrivateKeyInfo implements DEREncodable { } else { c = Cipher.getInstance(getAlgName(), provider); } + } catch (NoSuchPaddingException e) { + throw new NoSuchAlgorithmException(e); + } + try { c.init(Cipher.DECRYPT_MODE, decryptKey, getAlgParameters()); - encoded = c.doFinal(encryptedData); - return pkcs8EncodingToSpec(encoded); + return c.doFinal(encryptedData); + } catch (GeneralSecurityException e) { + throw new InvalidKeyException(e); + } + } + + // Wrap the decrypted encryptedData in a P8EKS for getKeySpec methods. + private PKCS8EncodedKeySpec getKeySpecImpl(Key decryptKey, + Provider provider) throws NoSuchAlgorithmException, + InvalidKeyException { + byte[] encoding = null; + try { + encoding = decryptData(decryptKey, provider); + return pkcs8EncodingToSpec(encoding); } catch (NoSuchAlgorithmException nsae) { // rethrow throw nsae; } catch (GeneralSecurityException | IOException ex) { throw new InvalidKeyException( - "Cannot retrieve the PKCS8EncodedKeySpec", ex); + "Cannot retrieve the PKCS8EncodedKeySpec", ex); + } finally { + KeyUtil.clear(encoding); } } /** - * Creates and encrypts an {@code EncryptedPrivateKeyInfo} from a given - * {@code PrivateKey}. A valid password-based encryption (PBE) algorithm + * Creates an {@code EncryptedPrivateKeyInfo} by encrypting the specified + * {@code DEREncodable}. A valid password-based encryption (PBE) algorithm * and password must be specified. * - *

    The PBE algorithm string format details can be found in the + *

    The format of the PBE algorithm string is described in the * - * Cipher section of the Java Security Standard Algorithm Names + * Cipher Algorithms section of the Java Security Standard Algorithm Names * Specification. * - * @param key the {@code PrivateKey} to be encrypted - * @param password the password used in the PBE encryption. This array - * will be cloned before being used. - * @param algorithm the PBE encryption algorithm. The default algorithm - * will be used if {@code null}. However, {@code null} is - * not allowed when {@code params} is non-null. - * @param params the {@code AlgorithmParameterSpec} to be used with - * encryption. The provider default will be used if - * {@code null}. - * @param provider the {@code Provider} will be used for PBE - * {@link SecretKeyFactory} generation and {@link Cipher} - * encryption operations. The default provider list will be - * used if {@code null}. + * @param de the {@code DEREncodable} to encrypt. Supported types include + * {@code PrivateKey}, {@code KeyPair}, and {@code PKCS8EncodedKeySpec}. + * @param password the password used for PBE encryption. This array is cloned + * before use. + * @param algorithm the PBE encryption algorithm + * @param params the {@code AlgorithmParameterSpec} used for encryption. If + * {@code null}, the provider’s default parameters are applied. + * @param provider the {@code Provider} for {@code SecretKeyFactory} and + * {@code Cipher} operations. If {@code null}, provider + * defaults are used. * @return an {@code EncryptedPrivateKeyInfo} - * @throws IllegalArgumentException on initialization errors based on the - * arguments passed to the method - * @throws RuntimeException on an encryption error - * @throws NullPointerException if the key or password are {@code null}. If - * {@code params} is non-null when {@code algorithm} is {@code null}. + * @throws NullPointerException if {@code de}, {@code password}, or + * {@code algorithm} is {@code null} + * @throws IllegalArgumentException if {@code de} is an unsupported + * {@code DEREncodable}, if an error occurs while generating the + * PBE key, if {@code algorithm} or {@code params} are + * not supported by any provider, or if an error occurs during + * encryption. * - * @implNote The {@code jdk.epkcs8.defaultAlgorithm} Security Property - * defines the default encryption algorithm and the - * {@code AlgorithmParameterSpec} are the provider's algorithm defaults. - * - * @since 25 + * @since 26 */ @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) - public static EncryptedPrivateKeyInfo encryptKey(PrivateKey key, + public static EncryptedPrivateKeyInfo encrypt(DEREncodable de, char[] password, String algorithm, AlgorithmParameterSpec params, Provider provider) { - SecretKey skey; - Objects.requireNonNull(key, "key cannot be null"); - Objects.requireNonNull(password, "password cannot be null."); - PBEKeySpec keySpec = new PBEKeySpec(password); - if (algorithm == null) { - if (params != null) { - throw new NullPointerException("algorithm must be specified" + - " if params is non-null."); - } - algorithm = Pem.DEFAULT_ALGO; - } - + Objects.requireNonNull(de, "a key must be specified."); + Objects.requireNonNull(password, "a password must be specified."); + Objects.requireNonNull(algorithm, "an algorithm must be specified."); + char[] passwd = password.clone(); + byte[] encoding = getEncoding(de); try { - SecretKeyFactory factory; - if (provider == null) { - factory = SecretKeyFactory.getInstance(algorithm); - } else { - factory = SecretKeyFactory.getInstance(algorithm, provider); - } - skey = factory.generateSecret(keySpec); - } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { - throw new IllegalArgumentException(e); + return encryptImpl(encoding, algorithm, + generateSecretKey(passwd, algorithm, provider), params, + provider, null); + } finally { + KeyUtil.clear(passwd, encoding); } - return encryptKeyImpl(key, algorithm, skey, params, provider, null); } - /** - * Creates and encrypts an {@code EncryptedPrivateKeyInfo} from a given - * {@code PrivateKey} and password. Default algorithm and parameters are - * used. + * Creates an {@code EncryptedPrivateKeyInfo} by encrypting the specified + * {@code DEREncodable}. A valid password must be specified. A default + * password-based encryption (PBE) algorithm and provider are used. * - * @param key the {@code PrivateKey} to be encrypted - * @param password the password used in the PBE encryption. This array - * will be cloned before being used. + * @param de the {@code DEREncodable} to encrypt. Supported types include + * {@code PrivateKey}, {@code KeyPair}, and {@code PKCS8EncodedKeySpec}. + * @param password the password used for PBE encryption. This array is cloned + * before use. * @return an {@code EncryptedPrivateKeyInfo} - * @throws IllegalArgumentException on initialization errors based on the - * arguments passed to the method - * @throws RuntimeException on an encryption error - * @throws NullPointerException when the {@code key} or {@code password} - * is {@code null} + * @throws NullPointerException if {@code de} or {@code password} is {@code null} + * @throws IllegalArgumentException if {@code de} is an unsupported + * {@code DEREncodable}, if an error occurs while generating the + * PBE key, or if the default algorithm is misconfigured * - * @implNote The {@code jdk.epkcs8.defaultAlgorithm} Security Property - * defines the default encryption algorithm and the - * {@code AlgorithmParameterSpec} are the provider's algorithm defaults. + * @implNote The {@code jdk.epkcs8.defaultAlgorithm} security property + * defines the default encryption algorithm. The {@code AlgorithmParameterSpec} + * defaults are determined by the provider. * - * @since 25 + * @since 26 */ @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) - public static EncryptedPrivateKeyInfo encryptKey(PrivateKey key, + public static EncryptedPrivateKeyInfo encrypt(DEREncodable de, char[] password) { - return encryptKey(key, password, Pem.DEFAULT_ALGO, null, null); + return encrypt(de, password, Pem.DEFAULT_ALGO, null, + null); } /** - * Creates and encrypts an {@code EncryptedPrivateKeyInfo} from the given - * {@link PrivateKey} using the {@code encKey} and given parameters. + * Creates an {@code EncryptedPrivateKeyInfo} by encrypting the specified + * {@code DEREncodable}. A valid encryption algorithm and {@code Key} must + * be specified. * - * @param key the {@code PrivateKey} to be encrypted - * @param encKey the password-based encryption (PBE) {@code Key} used to - * encrypt {@code key}. - * @param algorithm the PBE encryption algorithm. The default algorithm is - * will be used if {@code null}; however, {@code null} is - * not allowed when {@code params} is non-null. - * @param params the {@code AlgorithmParameterSpec} to be used with - * encryption. The provider list default will be used if - * {@code null}. - * @param random the {@code SecureRandom} instance used during - * encryption. The default will be used if {@code null}. - * @param provider the {@code Provider} is used for {@link Cipher} - * encryption operation. The default provider list will be - * used if {@code null}. + *

    The format of the algorithm string is described in the + * + * Cipher Algorithms section of the Java Security Standard Algorithm Names + * Specification. + * + * @param de the {@code DEREncodable} to encrypt. Supported types include + * {@code PrivateKey}, {@code KeyPair}, and {@code PKCS8EncodedKeySpec}. + * @param encryptKey the key used to encrypt the encoding + * @param algorithm the encryption algorithm, such as a password-based + * encryption (PBE) algorithm + * @param params the {@code AlgorithmParameterSpec} used for encryption. If + * {@code null}, the provider’s default parameters are applied. + * @param random the {@code SecureRandom} instance used during encryption. + * If {@code null}, the default is used. + * @param provider the {@code Provider} for {@code Cipher} operations. + * If {@code null}, the default provider list is used. * @return an {@code EncryptedPrivateKeyInfo} - * @throws IllegalArgumentException on initialization errors based on the - * arguments passed to the method - * @throws RuntimeException on an encryption error - * @throws NullPointerException if the {@code key} or {@code encKey} are - * {@code null}. If {@code params} is non-null, {@code algorithm} cannot be - * {@code null}. + * @throws NullPointerException if {@code de}, {@code encryptKey}, or + * {@code algorithm} is {@code null} + * @throws IllegalArgumentException if {@code de} is an unsupported + * {@code DEREncodable}, if {@code encryptKey} is invalid, if + * {@code algorithm} or {@code params} are not supported by any + * provider, or if an error occurs during encryption * - * @implNote The {@code jdk.epkcs8.defaultAlgorithm} Security Property - * defines the default encryption algorithm and the - * {@code AlgorithmParameterSpec} are the provider's algorithm defaults. - * - * @since 25 + * @since 26 */ @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) - public static EncryptedPrivateKeyInfo encryptKey(PrivateKey key, Key encKey, - String algorithm, AlgorithmParameterSpec params, Provider provider, - SecureRandom random) { + public static EncryptedPrivateKeyInfo encrypt(DEREncodable de, + Key encryptKey, String algorithm, AlgorithmParameterSpec params, + Provider provider, SecureRandom random) { - Objects.requireNonNull(key); - Objects.requireNonNull(encKey); - if (algorithm == null) { - if (params != null) { - throw new NullPointerException("algorithm must be specified " + - "if params is non-null."); - } - algorithm = Pem.DEFAULT_ALGO; - } - return encryptKeyImpl(key, algorithm, encKey, params, provider, random); + Objects.requireNonNull(de, "a key must be specified."); + Objects.requireNonNull(encryptKey, "an encryption key must be specified."); + Objects.requireNonNull(algorithm, "an algorithm must be specified."); + return encryptImpl(getEncoding(de), algorithm, encryptKey, + params, provider, random); } - private static EncryptedPrivateKeyInfo encryptKeyImpl(PrivateKey key, + private static EncryptedPrivateKeyInfo encryptImpl(byte[] encoded, String algorithm, Key encryptKey, AlgorithmParameterSpec params, Provider provider, SecureRandom random) { AlgorithmId algId; @@ -481,17 +474,26 @@ public non-sealed class EncryptedPrivateKeyInfo implements DEREncodable { c = Cipher.getInstance(algorithm, provider); } c.init(Cipher.ENCRYPT_MODE, encryptKey, params, random); - encryptedData = c.doFinal(key.getEncoded()); - algId = new AlgorithmId(Pem.getPBEID(algorithm), c.getParameters()); + encryptedData = c.doFinal(encoded); + try { + // Use shared PEM method for very likely case the algorithm is PBE. + algId = new AlgorithmId(Pem.getPBEID(algorithm), c.getParameters()); + } catch (IllegalArgumentException e) { + // For the unlikely case a non-PBE cipher is used, get the OID. + algId = new AlgorithmId(AlgorithmId.get(algorithm).getOID(), + c.getParameters()); + } out = new DerOutputStream(); algId.encode(out); out.putOctetString(encryptedData); } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | - NoSuchPaddingException e) { + IllegalStateException | NoSuchPaddingException | + IllegalBlockSizeException | InvalidKeyException e) { throw new IllegalArgumentException(e); - } catch (IllegalBlockSizeException | BadPaddingException | - InvalidKeyException e) { - throw new RuntimeException(e); + } catch (BadPaddingException e) { + throw new AssertionError(e); + } finally { + KeyUtil.clear(encoded); } return new EncryptedPrivateKeyInfo( DerValue.wrap(DerValue.tag_Sequence, out).toByteArray(), @@ -499,63 +501,129 @@ public non-sealed class EncryptedPrivateKeyInfo implements DEREncodable { } /** - * Extract the enclosed {@code PrivateKey} object from the encrypted data - * and return it. + * Extracts and returns the enclosed {@code PrivateKey} using the + * specified password. * - * @param password the password used in the PBE encryption. This array - * will be cloned before being used. - * @return a {@code PrivateKey} - * @throws GeneralSecurityException if an error occurs parsing or - * decrypting the encrypted data, or producing the key object. - * @throws NullPointerException if {@code password} is null + * @param password the password used for PBE decryption. The array is cloned + * before use. + * @return the decrypted {@code PrivateKey} + * @throws NullPointerException if {@code password} is {@code null} + * @throws NoSuchAlgorithmException if the decryption algorithm is unsupported + * @throws InvalidKeyException if an error occurs during parsing, + * decryption, or key generation * * @since 25 */ @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) - public PrivateKey getKey(char[] password) throws GeneralSecurityException { - SecretKeyFactory skf; - PKCS8EncodedKeySpec p8KeySpec; - Objects.requireNonNull(password, "password cannot be null"); + public PrivateKey getKey(char[] password) + throws NoSuchAlgorithmException, InvalidKeyException { + Objects.requireNonNull(password, "a password must be specified."); PBEKeySpec keySpec = new PBEKeySpec(password); - skf = SecretKeyFactory.getInstance(getAlgName()); - p8KeySpec = getKeySpec(skf.generateSecret(keySpec)); - - return PKCS8Key.parseKey(p8KeySpec.getEncoded()); + try { + return PKCS8Key.parseKey(Pem.decryptEncoding(this, keySpec), null); + } finally { + keySpec.clearPassword(); + } } /** - * Extract the enclosed {@code PrivateKey} object from the encrypted data - * and return it. + * Extracts and returns the enclosed {@code PrivateKey} using the specified + * decryption key and provider. * - * @param decryptKey the decryption key and cannot be {@code null} - * @param provider the {@code Provider} used for Cipher decryption and - * {@code PrivateKey} generation. A {@code null} value will - * use the default provider configuration. - * @return a {@code PrivateKey} - * @throws GeneralSecurityException if an error occurs parsing or - * decrypting the encrypted data, or producing the key object. - * @throws NullPointerException if {@code decryptKey} is null + * @param decryptKey the decryption key. Must not be {@code null}. + * @param provider the {@code Provider} for {@code Cipher} decryption + * and {@code PrivateKey} generation. If {@code null}, the + * default provider configuration is used. + * @return the decrypted {@code PrivateKey} + * @throws NullPointerException if {@code decryptKey} is {@code null} + * @throws NoSuchAlgorithmException if the decryption algorithm is unsupported + * @throws InvalidKeyException if an error occurs during parsing, + * decryption, or key generation * * @since 25 */ @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) public PrivateKey getKey(Key decryptKey, Provider provider) - throws GeneralSecurityException { - Objects.requireNonNull(decryptKey,"decryptKey cannot be null."); - PKCS8EncodedKeySpec p = getKeySpecImpl(decryptKey, provider); + throws NoSuchAlgorithmException, InvalidKeyException { + Objects.requireNonNull(decryptKey,"a decryptKey must be specified."); + byte[] encoding = null; try { - if (provider == null) { - return KeyFactory.getInstance( - KeyUtil.getAlgorithm(p.getEncoded())). - generatePrivate(p); - } - return KeyFactory.getInstance(KeyUtil.getAlgorithm(p.getEncoded()), - provider).generatePrivate(p); - } catch (IOException e) { - throw new GeneralSecurityException(e); + encoding = decryptData(decryptKey, provider); + return PKCS8Key.parseKey(encoding, provider); + } finally { + KeyUtil.clear(encoding); } } + /** + * Extracts and returns the enclosed {@code KeyPair} using the specified + * password. If the encoded data does not contain both a public and private + * key, an {@code InvalidKeyException} is thrown. + * + * @param password the password used for PBE decryption. The array is cloned + * before use. + * @return a decrypted {@code KeyPair} + * @throws NullPointerException if {@code password} is {@code null} + * @throws NoSuchAlgorithmException if the decryption algorithm is unsupported + * @throws InvalidKeyException if the encoded data lacks a public key, or if + * an error occurs during parsing, decryption, or key generation + * + * @since 26 + */ + @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) + public KeyPair getKeyPair(char[] password) + throws NoSuchAlgorithmException, InvalidKeyException { + Objects.requireNonNull(password, "a password must be specified."); + + PBEKeySpec keySpec = new PBEKeySpec(password); + DEREncodable d; + try { + d = Pem.toDEREncodable(Pem.decryptEncoding(this, keySpec), true, null); + } finally { + keySpec.clearPassword(); + } + return switch (d) { + case KeyPair kp -> kp; + case PrivateKey ignored -> throw new InvalidKeyException( + "This encoding does not contain a public key."); + default -> throw new InvalidKeyException( + "Invalid class returned " + d.getClass().getName()); + }; + } + + /** + * Extracts and returns the enclosed {@code KeyPair} using the specified + * decryption key and provider. If the encoded data does not contain both a + * public and private key, an {@code InvalidKeyException} is thrown. + * + * @param decryptKey the decryption key. Must not be {@code null}. + * @param provider the {@code Provider} for {@code Cipher} decryption + * and key generation. If {@code null}, the default provider + * configuration is used. + * @return a decrypted {@code KeyPair} + * @throws NullPointerException if {@code decryptKey} is {@code null} + * @throws NoSuchAlgorithmException if the decryption algorithm is unsupported + * @throws InvalidKeyException if the encoded data lacks a public key, or if + * an error occurs during parsing, decryption, or key generation + * + * @since 26 + */ + @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) + public KeyPair getKeyPair(Key decryptKey, Provider provider) + throws NoSuchAlgorithmException, InvalidKeyException { + Objects.requireNonNull(decryptKey,"a decryptKey must be specified."); + + DEREncodable d = Pem.toDEREncodable( + decryptData(decryptKey, provider),true, provider); + return switch (d) { + case KeyPair kp -> kp; + case PrivateKey ignored -> throw new InvalidKeyException( + "This encoding does not contain a public key."); + default -> throw new InvalidKeyException( + "Invalid class returned " + d.getClass().getName()); + }; + } + /** * Extract the enclosed PKCS8EncodedKeySpec object from the * encrypted data and return it. @@ -585,7 +653,7 @@ public non-sealed class EncryptedPrivateKeyInfo implements DEREncodable { * @param decryptKey key used for decrypting the encrypted data. * @param providerName the name of provider whose cipher * implementation will be used. - * @return the PKCS8EncodedKeySpec object. + * @return the PKCS8EncodedKeySpec object * @exception NullPointerException if {@code decryptKey} * or {@code providerName} is {@code null}. * @exception NoSuchProviderException if no provider @@ -670,17 +738,48 @@ public non-sealed class EncryptedPrivateKeyInfo implements DEREncodable { return this.encoded.clone(); } - private static void checkTag(DerValue val, byte tag, String valName) - throws IOException { - if (val.getTag() != tag) { - throw new IOException("invalid key encoding - wrong tag for " + - valName); - } - } - + // Read the encodedKey and return a P8EKS with the algorithm specified private static PKCS8EncodedKeySpec pkcs8EncodingToSpec(byte[] encodedKey) throws IOException { return new PKCS8EncodedKeySpec(encodedKey, KeyUtil.getAlgorithm(encodedKey)); } + + // Return the PKCS#8 encoding from a DEREncodable + private static byte[] getEncoding(DEREncodable d) { + return switch (d) { + case PrivateKey p -> p.getEncoded(); + case PKCS8EncodedKeySpec p8 -> p8.getEncoded(); + case KeyPair kp -> { + try { + yield PKCS8Key.getEncoded(kp.getPublic().getEncoded(), + kp.getPrivate().getEncoded()); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + default -> throw new IllegalArgumentException( + d.getClass().getName() + " not supported by this method"); + }; + } + + // Generate a SecretKey from the password. + private static SecretKey generateSecretKey(char[] password, String algorithm, + Provider provider) { + PBEKeySpec keySpec = new PBEKeySpec(password); + + try { + SecretKeyFactory factory; + if (provider == null) { + factory = SecretKeyFactory.getInstance(algorithm); + } else { + factory = SecretKeyFactory.getInstance(algorithm, provider); + } + return factory.generateSecret(keySpec); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + throw new IllegalArgumentException(e); + } finally { + keySpec.clearPassword(); + } + } } diff --git a/src/java.base/share/classes/javax/crypto/JceSecurity.java.template b/src/java.base/share/classes/javax/crypto/JceSecurity.java.template index 01282394b57..a6010945660 100644 --- a/src/java.base/share/classes/javax/crypto/JceSecurity.java.template +++ b/src/java.base/share/classes/javax/crypto/JceSecurity.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * * In the current jdk builds, this file is first preprocessed to replace * @@JCE_DEFAULT_POLICY@ [sic] with "limited" or "unlimited" which is - * determined by the $(UNLIMTED_CRYPTO) make variable. This variable is + * determined by the $(UNLIMITED_CRYPTO) make variable. This variable is * set by top-level configure script, using either * --disable-unlimited-crypto or --enable-unlimited-crypto [default]. * diff --git a/src/java.base/share/classes/javax/crypto/spec/HPKEParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/HPKEParameterSpec.java new file mode 100644 index 00000000000..6776ddcdb75 --- /dev/null +++ b/src/java.base/share/classes/javax/crypto/spec/HPKEParameterSpec.java @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2025, 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 javax.crypto.spec; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.security.AsymmetricKey; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.Objects; + +/** + * This immutable class specifies the set of parameters used with a {@code Cipher} for the + * Hybrid Public Key Encryption + * (HPKE) algorithm. HPKE is a public key encryption scheme for encrypting + * arbitrary-sized plaintexts with a recipient's public key. It combines a key + * encapsulation mechanism (KEM), a key derivation function (KDF), and an + * authenticated encryption with additional data (AEAD) cipher. + *

    + * The + * standard algorithm name for the cipher is "HPKE". Unlike most other + * ciphers, HPKE is not expressed as a transformation string of the form + * "algorithm/mode/padding". Therefore, the argument to {@code Cipher.getInstance} + * must be the single algorithm name "HPKE". + *

    + * In HPKE, the sender's {@code Cipher} is always initialized with the + * recipient's public key in {@linkplain Cipher#ENCRYPT_MODE encrypt mode}, + * while the recipient's {@code Cipher} object is initialized with its own + * private key in {@linkplain Cipher#DECRYPT_MODE decrypt mode}. + *

    + * An {@code HPKEParameterSpec} object must be provided at HPKE + * {@linkplain Cipher#init(int, Key, AlgorithmParameterSpec) cipher initialization}. + *

    + * The {@link #of(int, int, int)} static method returns an {@code HPKEParameterSpec} + * object with the specified KEM, KDF, and AEAD algorithm identifiers. + * The terms "KEM algorithm identifiers", "KDF algorithm identifiers", and + * "AEAD algorithm identifiers" refer to their respective numeric values + * (specifically, {@code kem_id}, {@code kdf_id}, and {@code aead_id}) as + * defined in Section 7 + * of RFC 9180 and maintained on the + * IANA HPKE page. + *

    + * Once an {@code HPKEParameterSpec} object is created, additional methods + * are available to generate new {@code HPKEParameterSpec} objects with + * different features: + *

      + *
    • + * Application-supplied information can be provided using the + * {@link #withInfo(byte[])} method by both sides. + *
    • + * To authenticate using a pre-shared key ({@code mode_psk}), the + * pre-shared key and its identifier must be provided using the + * {@link #withPsk(SecretKey, byte[])} method by both sides. + *
    • + * To authenticate using an asymmetric key ({@code mode_auth}), + * the asymmetric keys must be provided using the {@link #withAuthKey(AsymmetricKey)} + * method. Precisely, the sender must call this method with its own private key + * and the recipient must call it with the sender's public key. + *
    • + * To authenticate using both a PSK and an asymmetric key + * ({@code mode_auth_psk}), both {@link #withAuthKey(AsymmetricKey)} and + * {@link #withPsk(SecretKey, byte[])} methods must be called as described above. + *
    • + * In HPKE, a shared secret is negotiated during the KEM step and a key + * encapsulation message must be transmitted from the sender to the recipient + * so that the recipient can recover the shared secret. On the sender side, + * after the cipher is initialized, the key encapsulation message can be + * retrieved using the {@link Cipher#getIV()} method. On the recipient side, + * this message must be supplied as part of an {@code HPKEParameterSpec} + * object obtained from the {@link #withEncapsulation(byte[])} method. + *
    + * For successful interoperability, both sides need to have identical algorithm + * identifiers, and supply identical + * {@code info}, {@code psk}, and {@code psk_id} or matching authentication + * keys if provided. For details about HPKE modes, refer to + * Section 5 + * of RFC 9180. + *

    + * If an HPKE cipher is {@linkplain Cipher#init(int, Key) initialized without + * parameters}, an {@code InvalidKeyException} is thrown. + *

    + * At HPKE cipher initialization, if no HPKE implementation supports the + * provided key type, an {@code InvalidKeyException} is thrown. If the provided + * {@code HPKEParameterSpec} is not accepted by any HPKE implementation, + * an {@code InvalidAlgorithmParameterException} is thrown. For example: + *

      + *
    • An algorithm identifier is unsupported or does not match the provided key type. + *
    • A key encapsulation message is provided on the sender side. + *
    • A key encapsulation message is not provided on the recipient side. + *
    • An attempt to use {@code withAuthKey(key)} is made with an incompatible key. + *
    • An attempt to use {@code withAuthKey(key)} is made but {@code mode_auth} + * or {@code mode_auth_psk} is not supported by the KEM algorithm used. + *
    + * After initialization, both the sender and recipient can process multiple + * messages in sequence with repeated {@code doFinal} calls, optionally preceded + * by one or more {@code updateAAD} and {@code update}. Each {@code doFinal} + * performs a complete HPKE encryption or decryption operation using a distinct + * IV derived from an internal sequence counter, as specified in + * Section 5.2 + * of RFC 9180. On the recipient side, each {@code doFinal} call must correspond + * to exactly one complete ciphertext, and the number and order of calls must + * match those on the sender side. This differs from the direct use of an AEAD + * cipher, where the caller must provide a fresh IV and reinitialize the cipher + * for each message. By managing IVs internally, HPKE allows a single + * initialization to support multiple messages while still ensuring IV + * uniqueness and preserving AEAD security guarantees. + *

    + * This example shows a sender and a recipient using HPKE to securely exchange + * messages with an X25519 key pair. + * {@snippet lang=java class="PackageSnippets" region="hpke-spec-example"} + * + * @implNote This class defines constants for some of the standard algorithm + * identifiers such as {@link #KEM_DHKEM_P_256_HKDF_SHA256}, + * {@link #KDF_HKDF_SHA256}, and {@link #AEAD_AES_128_GCM}. An HPKE {@code Cipher} + * implementation may support all, some, or none of the algorithm identifiers + * defined here. An implementation may also support additional identifiers not + * listed here, including private or experimental values. + * + * @spec https://www.rfc-editor.org/info/rfc9180 + * RFC 9180: Hybrid Public Key Encryption + * @spec security/standard-names.html + * Java Security Standard Algorithm Names + * @since 26 + */ +public final class HPKEParameterSpec implements AlgorithmParameterSpec { + + /** + * KEM algorithm identifier for DHKEM(P-256, HKDF-SHA256) as defined in RFC 9180. + */ + public static final int KEM_DHKEM_P_256_HKDF_SHA256 = 0x10; + + /** + * KEM algorithm identifier for DHKEM(P-384, HKDF-SHA384) as defined in RFC 9180. + */ + public static final int KEM_DHKEM_P_384_HKDF_SHA384 = 0x11; + + /** + * KEM algorithm identifier for DHKEM(P-521, HKDF-SHA512) as defined in RFC 9180. + */ + public static final int KEM_DHKEM_P_521_HKDF_SHA512 = 0x12; + + /** + * KEM algorithm identifier for DHKEM(X25519, HKDF-SHA256) as defined in RFC 9180. + */ + public static final int KEM_DHKEM_X25519_HKDF_SHA256 = 0x20; + + /** + * KEM algorithm identifier for DHKEM(X448, HKDF-SHA512) as defined in RFC 9180. + */ + public static final int KEM_DHKEM_X448_HKDF_SHA512 = 0x21; + + /** + * KDF algorithm identifier for HKDF-SHA256 as defined in RFC 9180. + */ + public static final int KDF_HKDF_SHA256 = 0x1; + + /** + * KDF algorithm identifier for HKDF-SHA384 as defined in RFC 9180. + */ + public static final int KDF_HKDF_SHA384 = 0x2; + + /** + * KDF algorithm identifier for HKDF-SHA512 as defined in RFC 9180. + */ + public static final int KDF_HKDF_SHA512 = 0x3; + + /** + * AEAD algorithm identifier for AES-128-GCM as defined in RFC 9180. + */ + public static final int AEAD_AES_128_GCM = 0x1; + + /** + * AEAD algorithm identifier for AES-256-GCM as defined in RFC 9180. + */ + public static final int AEAD_AES_256_GCM = 0x2; + + /** + * AEAD algorithm identifier for ChaCha20Poly1305 as defined in RFC 9180. + */ + public static final int AEAD_CHACHA20_POLY1305 = 0x3; + + /** + * AEAD algorithm identifier for Export-only as defined in RFC 9180. + */ + public static final int EXPORT_ONLY = 0xffff; + + private final int kem_id; + private final int kdf_id; + private final int aead_id; + private final byte[] info; // never null, can be empty + private final SecretKey psk; // null if not used + private final byte[] psk_id; // never null, can be empty + private final AsymmetricKey kS; // null if not used + private final byte[] encapsulation; // null if none + + // Note: this constructor does not clone array arguments. + private HPKEParameterSpec(int kem_id, int kdf_id, int aead_id, byte[] info, + SecretKey psk, byte[] psk_id, AsymmetricKey kS, byte[] encapsulation) { + this.kem_id = kem_id; + this.kdf_id = kdf_id; + this.aead_id = aead_id; + this.info = info; + this.psk = psk; + this.psk_id = psk_id; + this.kS = kS; + this.encapsulation = encapsulation; + } + + /** + * A factory method to create a new {@code HPKEParameterSpec} object with + * specified KEM, KDF, and AEAD algorithm identifiers in {@code mode_base} + * mode with an empty {@code info}. + * + * @param kem_id algorithm identifier for KEM, must be between 0 and 65535 (inclusive) + * @param kdf_id algorithm identifier for KDF, must be between 0 and 65535 (inclusive) + * @param aead_id algorithm identifier for AEAD, must be between 0 and 65535 (inclusive) + * @return a new {@code HPKEParameterSpec} object + * @throws IllegalArgumentException if any input value + * is out of range (must be between 0 and 65535, inclusive). + */ + public static HPKEParameterSpec of(int kem_id, int kdf_id, int aead_id) { + if (kem_id < 0 || kem_id > 65535) { + throw new IllegalArgumentException("Invalid kem_id: " + kem_id); + } + if (kdf_id < 0 || kdf_id > 65535) { + throw new IllegalArgumentException("Invalid kdf_id: " + kdf_id); + } + if (aead_id < 0 || aead_id > 65535) { + throw new IllegalArgumentException("Invalid aead_id: " + aead_id); + } + return new HPKEParameterSpec(kem_id, kdf_id, aead_id, + new byte[0], null, new byte[0], null, null); + } + + /** + * Creates a new {@code HPKEParameterSpec} object with the specified + * {@code info} value. + *

    + * For interoperability, RFC 9180 Section 7.2.1 recommends limiting + * this value to a maximum of 64 bytes. + * + * @param info application-supplied information. + * The contents of the array are copied to protect + * against subsequent modification. + * @return a new {@code HPKEParameterSpec} object + * @throws NullPointerException if {@code info} is {@code null} + * @throws IllegalArgumentException if {@code info} is empty. + */ + public HPKEParameterSpec withInfo(byte[] info) { + Objects.requireNonNull(info); + if (info.length == 0) { + throw new IllegalArgumentException("info is empty"); + } + return new HPKEParameterSpec(kem_id, kdf_id, aead_id, + info.clone(), psk, psk_id, kS, encapsulation); + } + + /** + * Creates a new {@code HPKEParameterSpec} object with the specified + * {@code psk} and {@code psk_id} values. + *

    + * RFC 9180 Section 5.1.2 requires the PSK MUST have at least 32 bytes + * of entropy. For interoperability, RFC 9180 Section 7.2.1 recommends + * limiting the key size and identifier length to a maximum of 64 bytes. + * + * @param psk pre-shared key + * @param psk_id identifier for PSK. The contents of the array are copied + * to protect against subsequent modification. + * @return a new {@code HPKEParameterSpec} object + * @throws NullPointerException if {@code psk} or {@code psk_id} is {@code null} + * @throws IllegalArgumentException if {@code psk} is shorter than 32 bytes + * or {@code psk_id} is empty + */ + public HPKEParameterSpec withPsk(SecretKey psk, byte[] psk_id) { + Objects.requireNonNull(psk); + Objects.requireNonNull(psk_id); + if (psk_id.length == 0) { + throw new IllegalArgumentException("psk_id is empty"); + } + if ("RAW".equalsIgnoreCase(psk.getFormat())) { + // We can only check when psk is extractable. We can only + // check the length and not the real entropy size + var keyBytes = psk.getEncoded(); + assert keyBytes != null; + Arrays.fill(keyBytes, (byte)0); + if (keyBytes.length < 32) { + throw new IllegalArgumentException("psk is too short"); + } + } + return new HPKEParameterSpec(kem_id, kdf_id, aead_id, + info, psk, psk_id.clone(), kS, encapsulation); + } + + /** + * Creates a new {@code HPKEParameterSpec} object with the specified + * key encapsulation message value that will be used by the recipient. + * + * @param encapsulation the key encapsulation message. + * The contents of the array are copied to protect against + * subsequent modification. + * + * @return a new {@code HPKEParameterSpec} object + * @throws NullPointerException if {@code encapsulation} is {@code null} + */ + public HPKEParameterSpec withEncapsulation(byte[] encapsulation) { + return new HPKEParameterSpec(kem_id, kdf_id, aead_id, + info, psk, psk_id, kS, + Objects.requireNonNull(encapsulation).clone()); + } + + /** + * Creates a new {@code HPKEParameterSpec} object with the specified + * authentication key value. + *

    + * Note: this method does not check whether the KEM algorithm supports + * {@code mode_auth} or {@code mode_auth_psk}. If the resulting object is + * used to initialize an HPKE cipher with an unsupported mode, an + * {@code InvalidAlgorithmParameterException} will be thrown at that time. + * + * @param kS the authentication key + * @return a new {@code HPKEParameterSpec} object + * @throws NullPointerException if {@code kS} is {@code null} + */ + public HPKEParameterSpec withAuthKey(AsymmetricKey kS) { + return new HPKEParameterSpec(kem_id, kdf_id, aead_id, + info, psk, psk_id, + Objects.requireNonNull(kS), + encapsulation); + } + + /** + * {@return the algorithm identifier for KEM } + */ + public int kem_id() { + return kem_id; + } + + /** + * {@return the algorithm identifier for KDF } + */ + public int kdf_id() { + return kdf_id; + } + + /** + * {@return the algorithm identifier for AEAD } + */ + public int aead_id() { + return aead_id; + } + + /** + * {@return a copy of the application-supplied information, empty if none} + */ + public byte[] info() { + return info.clone(); + } + + /** + * {@return pre-shared key, {@code null} if none} + */ + public SecretKey psk() { + return psk; + } + + /** + * {@return a copy of the identifier for PSK, empty if none} + */ + public byte[] psk_id() { + return psk_id.clone(); + } + + /** + * {@return the key for authentication, {@code null} if none} + */ + public AsymmetricKey authKey() { + return kS; + } + + /** + * {@return a copy of the key encapsulation message, {@code null} if none} + */ + public byte[] encapsulation() { + return encapsulation == null ? null : encapsulation.clone(); + } + + @Override + public String toString() { + return "HPKEParameterSpec{" + + "kem_id=" + kem_id + + ", kdf_id=" + kdf_id + + ", aead_id=" + aead_id + + ", info=" + bytesToString(info) + + ", " + (psk == null + ? (kS == null ? "mode_base" : "mode_auth") + : (kS == null ? "mode_psk" : "mode_auth_psk")) + "}"; + } + + // Returns a human-readable representation of a byte array. + private static String bytesToString(byte[] input) { + if (input.length == 0) { + return "(empty)"; + } else { + for (byte b : input) { + if (b < 0x20 || b > 0x7E || b == '"') { + // Non-ASCII or control characters are hard to read, and + // `"` requires character escaping. If any of these are + // present, return only the HEX representation. + return HexFormat.of().formatHex(input); + } + } + // Otherwise, all characters are printable and safe. + // Return both HEX and ASCII representations. + return HexFormat.of().formatHex(input) + + " (\"" + new String(input, StandardCharsets.US_ASCII) + "\")"; + } + } +} diff --git a/src/java.base/share/classes/javax/crypto/spec/snippet-files/PackageSnippets.java b/src/java.base/share/classes/javax/crypto/spec/snippet-files/PackageSnippets.java new file mode 100644 index 00000000000..e4074c1c4a9 --- /dev/null +++ b/src/java.base/share/classes/javax/crypto/spec/snippet-files/PackageSnippets.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025, 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. + */ +import javax.crypto.Cipher; +import javax.crypto.spec.HPKEParameterSpec; +import java.nio.charset.StandardCharsets; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.util.Arrays; +import java.util.HexFormat; + +class PackageSnippets { + public static void main(String[] args) throws Exception { + + // @start region="hpke-spec-example" + // Recipient key pair generation + KeyPairGenerator g = KeyPairGenerator.getInstance("X25519"); + KeyPair kp = g.generateKeyPair(); + + // The HPKE sender cipher is initialized with the recipient's public + // key and an HPKEParameterSpec using specified algorithm identifiers + // and application-supplied info. + Cipher senderCipher = Cipher.getInstance("HPKE"); + HPKEParameterSpec ps = HPKEParameterSpec.of( + HPKEParameterSpec.KEM_DHKEM_X25519_HKDF_SHA256, + HPKEParameterSpec.KDF_HKDF_SHA256, + HPKEParameterSpec.AEAD_AES_128_GCM) + .withInfo(HexFormat.of().parseHex("010203040506")); + senderCipher.init(Cipher.ENCRYPT_MODE, kp.getPublic(), ps); + + // Retrieve the key encapsulation message (from the KEM step) from + // the sender. + byte[] kemEncap = senderCipher.getIV(); + + // The HPKE recipient cipher is initialized with its own private key, + // an HPKEParameterSpec using the same algorithm identifiers as used by + // the sender, and the key encapsulation message from the sender. + Cipher recipientCipher = Cipher.getInstance("HPKE"); + HPKEParameterSpec pr = HPKEParameterSpec.of( + HPKEParameterSpec.KEM_DHKEM_X25519_HKDF_SHA256, + HPKEParameterSpec.KDF_HKDF_SHA256, + HPKEParameterSpec.AEAD_AES_128_GCM) + .withInfo(HexFormat.of().parseHex("010203040506")) + .withEncapsulation(kemEncap); + recipientCipher.init(Cipher.DECRYPT_MODE, kp.getPrivate(), pr); + + // Encryption and decryption + byte[] msg = "Hello World".getBytes(StandardCharsets.UTF_8); + byte[] ct = senderCipher.doFinal(msg); + byte[] pt = recipientCipher.doFinal(ct); + + assert Arrays.equals(msg, pt); + // @end + } +} diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index fa6e5b4aac3..86e5f317dc7 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -205,7 +205,7 @@ public interface JavaLangAccess { * Updates the readability so that module m1 reads m2. The new read edge * does not result in a strong reference to m2 (m2 can be GC'ed). * - * This method is the same as m1.addReads(m2) but without a permission check. + * This method is the same as m1.addReads(m2) but without a caller check. */ void addReads(Module m1, Module m2); @@ -259,11 +259,11 @@ public interface JavaLangAccess { /** * Updates module m to allow access to restricted methods. */ - Module addEnableNativeAccess(Module m); + void addEnableNativeAccess(Module m); /** - * Updates module named {@code name} in layer {@code layer} to allow access to restricted methods. - * Returns true iff the given module exists in the given layer. + * Updates module named {@code name} in layer {@code layer} to allow access to + * restricted methods. Returns true iff the given module exists in the given layer. */ boolean addEnableNativeAccess(ModuleLayer layer, String name); @@ -273,7 +273,8 @@ public interface JavaLangAccess { void addEnableNativeAccessToAllUnnamed(); /** - * Ensure that the given module has native access. If not, warn or throw exception depending on the configuration. + * Ensure that the given module has native access. If not, warn or throw exception + * depending on the configuration. * @param m the module in which native access occurred * @param owner the owner of the restricted method being called (or the JNI method being bound) * @param methodName the name of the restricted method being called (or the JNI method being bound) @@ -282,6 +283,31 @@ public interface JavaLangAccess { */ void ensureNativeAccess(Module m, Class owner, String methodName, Class currentClass, boolean jni); + /** + * Enable code in all unnamed modules to mutate final instance fields. + */ + void addEnableFinalMutationToAllUnnamed(); + + /** + * Enable code in a given module to mutate final instance fields. + */ + boolean tryEnableFinalMutation(Module m); + + /** + * Return true if code in a given module is allowed to mutate final instance fields. + */ + boolean isFinalMutationEnabled(Module m); + + /** + * Return true if a given module has statically exported the given package to a given other module. + */ + boolean isStaticallyExported(Module module, String pn, Module other); + + /** + * Return true if a given module has statically opened the given package to a given other module. + */ + boolean isStaticallyOpened(Module module, String pn, Module other); + /** * Returns the ServicesCatalog for the given Layer. */ diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java index d0c415d2dc6..965bac67f45 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -67,4 +67,10 @@ public interface JavaLangReflectAccess { /** Returns a new instance created by the given constructor with access check */ public T newInstance(Constructor ctor, Object[] args, Class caller) throws IllegalAccessException, InstantiationException, InvocationTargetException; + + /** + * Check that the caller is allowed to unreflect for mutation a final instance field + * in a class that is not a record or hidden class. + */ + void checkAllowedToUnreflectFinalSetter(Class caller, Field f) throws IllegalAccessException; } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaUtilCollectionAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaUtilCollectionAccess.java index cac8785b158..5e7647d6106 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaUtilCollectionAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaUtilCollectionAccess.java @@ -26,14 +26,8 @@ package jdk.internal.access; import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.function.IntFunction; public interface JavaUtilCollectionAccess { List listFromTrustedArray(Object[] array); List listFromTrustedArrayNullsAllowed(Object[] array); - List stableList(int size, IntFunction mapper); - Map stableMap(Set keys, Function mapper); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index 962a2057585..ec747d06c21 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -35,6 +35,7 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.constant.ClassOrInterfaceDescImpl; import jdk.internal.constant.PrimitiveClassDescImpl; import jdk.internal.util.ArraysSupport; +import jdk.internal.util.ModifiedUtf; import jdk.internal.vm.annotation.Stable; import static java.util.Objects.requireNonNull; @@ -141,7 +142,7 @@ public abstract sealed class AbstractPoolEntry { @Stable TypeDescriptor typeSym; Utf8EntryImpl(ConstantPool cpm, int index, - byte[] rawBytes, int offset, int rawLen) { + byte[] rawBytes, int offset, int rawLen) { super(cpm, index, 0); this.rawBytes = rawBytes; this.offset = offset; @@ -154,6 +155,10 @@ public abstract sealed class AbstractPoolEntry { } Utf8EntryImpl(ConstantPool cpm, int index, String s, int contentHash) { + // Prevent creation of unwritable entries + if (!ModifiedUtf.isValidLengthInConstantPool(s)) { + throw new IllegalArgumentException("utf8 length out of range of u2: " + ModifiedUtf.utfLen(s)); + } super(cpm, index, 0); this.rawBytes = null; this.offset = 0; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java index b30592a4ebd..6daef5cab9a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java @@ -277,10 +277,9 @@ public final class BufWriterImpl implements BufWriter { int strlen = str.length(); int countNonZeroAscii = JLA.countNonZeroAscii(str); long utflenLong = utfLen(str, countNonZeroAscii); - if (!ExactConversionsSupport.isLongToCharExact(utflenLong)) { - throw new IllegalArgumentException("utf8 length out of range of u2: " + utflenLong); - } - int utflen = (int)utflenLong; + // Utf8Entry should always be writable + assert ExactConversionsSupport.isLongToCharExact(utflenLong) : utflenLong; + int utflen = (int) utflenLong; reserveSpace(utflen + 3); int offset = this.offset; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java index 5be14f42baa..e4e67afb17f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,11 @@ */ package jdk.internal.classfile.impl; -import java.io.BufferedInputStream; -import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; import java.lang.classfile.ClassHierarchyResolver; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ClassDesc; import java.util.Collection; import java.util.HashMap; @@ -38,7 +37,6 @@ import java.util.Map; import java.util.function.Function; import static java.lang.classfile.ClassFile.ACC_INTERFACE; -import static java.lang.classfile.constantpool.PoolEntry.*; import static java.lang.constant.ConstantDescs.CD_Object; import static java.util.Objects.requireNonNull; import static jdk.internal.constant.ConstantUtils.referenceClassDesc; @@ -164,31 +162,12 @@ public final class ClassHierarchyImpl { public ClassHierarchyResolver.ClassHierarchyInfo getClassInfo(ClassDesc classDesc) { var ci = streamProvider.apply(classDesc); if (ci == null) return null; - try (var in = new DataInputStream(new BufferedInputStream(ci))) { - in.skipBytes(8); - int cpLength = in.readUnsignedShort(); - String[] cpStrings = new String[cpLength]; - int[] cpClasses = new int[cpLength]; - for (int i = 1; i < cpLength; i++) { - int tag; - switch (tag = in.readUnsignedByte()) { - case TAG_UTF8 -> cpStrings[i] = in.readUTF(); - case TAG_CLASS -> cpClasses[i] = in.readUnsignedShort(); - case TAG_STRING, TAG_METHOD_TYPE, TAG_MODULE, TAG_PACKAGE -> in.skipBytes(2); - case TAG_METHOD_HANDLE -> in.skipBytes(3); - case TAG_INTEGER, TAG_FLOAT, TAG_FIELDREF, TAG_METHODREF, TAG_INTERFACE_METHODREF, - TAG_NAME_AND_TYPE, TAG_DYNAMIC, TAG_INVOKE_DYNAMIC -> in.skipBytes(4); - case TAG_LONG, TAG_DOUBLE -> { - in.skipBytes(8); - i++; - } - default -> throw new IllegalStateException("Bad tag (" + tag + ") at index (" + i + ")"); - } - } - boolean isInterface = (in.readUnsignedShort() & ACC_INTERFACE) != 0; - in.skipBytes(2); - int superIndex = in.readUnsignedShort(); - var superClass = superIndex > 0 ? ClassDesc.ofInternalName(cpStrings[cpClasses[superIndex]]) : null; + try (ci) { + var reader = new ClassReaderImpl(ci.readAllBytes(), ClassFileImpl.DEFAULT_CONTEXT); + boolean isInterface = (reader.flags() & ACC_INTERFACE) != 0; + ClassDesc superClass = reader.superclassEntry() + .map(ClassEntry::asSymbol) + .orElse(null); return new ClassHierarchyInfoImpl(superClass, isInterface); } catch (IOException ioe) { throw new UncheckedIOException(ioe); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java index 23387fcb098..4cb0517ec76 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -120,9 +120,9 @@ public final class TransformImpl { @Override public ClassTransform andThen(ClassTransform next) { - if (next instanceof ClassMethodTransform cmt) - return new ClassMethodTransform(transform.andThen(cmt.transform), - mm -> filter.test(mm) && cmt.filter.test(mm)); + // Optimized for shared _ -> true filter in ClassTransform.transformingMethods(MethodTransform) + if (next instanceof ClassMethodTransform(var nextTransform, var nextFilter) && filter == nextFilter) + return new ClassMethodTransform(transform.andThen(nextTransform), filter); else return UnresolvedClassTransform.super.andThen(next); } @@ -143,9 +143,9 @@ public final class TransformImpl { @Override public ClassTransform andThen(ClassTransform next) { - if (next instanceof ClassFieldTransform cft) - return new ClassFieldTransform(transform.andThen(cft.transform), - mm -> filter.test(mm) && cft.filter.test(mm)); + // Optimized for shared _ -> true filter in ClassTransform.transformingFields(FieldTransform) + if (next instanceof ClassFieldTransform(var nextTransform, var nextFilter) && filter == nextFilter) + return new ClassFieldTransform(transform.andThen(nextTransform), filter); else return UnresolvedClassTransform.super.andThen(next); } @@ -208,8 +208,8 @@ public final class TransformImpl { @Override public MethodTransform andThen(MethodTransform next) { - return (next instanceof TransformImpl.MethodCodeTransform mct) - ? new TransformImpl.MethodCodeTransform(xform.andThen(mct.xform)) + return (next instanceof MethodCodeTransform(var nextXform)) + ? new TransformImpl.MethodCodeTransform(xform.andThen(nextXform)) : UnresolvedMethodTransform.super.andThen(next); } diff --git a/src/java.base/share/classes/jdk/internal/event/FinalFieldMutationEvent.java b/src/java.base/share/classes/jdk/internal/event/FinalFieldMutationEvent.java new file mode 100644 index 00000000000..4db29d43bd6 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/event/FinalFieldMutationEvent.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, 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 jdk.internal.event; + +public class FinalFieldMutationEvent extends Event { + public Class declaringClass; + public String fieldName; + + /** + * Commit a FinalFieldMutationEvent if enabled. + */ + public static void offer(Class declaringClass, String fieldName) { + if (enabled()) { + var event = new FinalFieldMutationEvent(); + event.declaringClass = declaringClass; + event.fieldName = fieldName; + event.commit(); + } + } + + public static boolean enabled() { + // Generated by JFR + return false; + } +} diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index d7636032c28..a0c8a0a5a4f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -33,6 +33,7 @@ import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.util.ArraysSupport; import jdk.internal.util.Preconditions; +import jdk.internal.vm.annotation.DontInline; import jdk.internal.vm.annotation.ForceInline; import sun.nio.ch.DirectBuffer; @@ -68,7 +69,7 @@ import java.util.stream.StreamSupport; * {@link MappedMemorySegmentImpl}. */ public abstract sealed class AbstractMemorySegmentImpl - implements MemorySegment, SegmentAllocator, BiFunction, RuntimeException> + implements MemorySegment, SegmentAllocator permits HeapMemorySegmentImpl, NativeMemorySegmentImpl { static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess(); @@ -100,19 +101,19 @@ public abstract sealed class AbstractMemorySegmentImpl @Override public AbstractMemorySegmentImpl asSlice(long offset, long newSize) { - checkBounds(offset, newSize); + checkSliceBounds(offset, newSize); return asSliceNoCheck(offset, newSize); } @Override public AbstractMemorySegmentImpl asSlice(long offset) { - checkBounds(offset, 0); + checkSliceBounds(offset, 0); return asSliceNoCheck(offset, length - offset); } @Override public MemorySegment asSlice(long offset, long newSize, long byteAlignment) { - checkBounds(offset, newSize); + checkSliceBounds(offset, newSize); Utils.checkAlign(byteAlignment); if (!isAlignedForElement(offset, byteAlignment)) { @@ -354,7 +355,7 @@ public abstract sealed class AbstractMemorySegmentImpl @ForceInline public void checkAccess(long offset, long length, boolean readOnly) { checkReadOnly(readOnly); - checkBounds(offset, length); + checkAccessBounds(offset, length); } @ForceInline @@ -398,20 +399,40 @@ public abstract sealed class AbstractMemorySegmentImpl } @ForceInline - void checkBounds(long offset, long length) { - if (length > 0) { - Preconditions.checkIndex(offset, this.length - length + 1, this); - } else if (length < 0 || offset < 0 || - offset > this.length - length) { - throw outOfBoundException(offset, length); + void checkSliceBounds(long offset, long length) { + try { + checkBounds(offset, length); + } catch (IndexOutOfBoundsException e) { + throwOutOfBounds(offset, length, /* isSlice = */ true); } } - @Override - public RuntimeException apply(String s, List numbers) { - long offset = numbers.get(0).longValue(); - long length = byteSize() - numbers.get(1).longValue() + 1; - return outOfBoundException(offset, length); + @ForceInline + void checkAccessBounds(long offset, long length) { + try { + checkBounds(offset, length); + } catch (IndexOutOfBoundsException e) { + throwOutOfBounds(offset, length, /* isSlice = */ false); + } + } + + @ForceInline + private void checkBounds(long offset, long length) { + if (length > 0) { + Preconditions.checkIndex(offset, this.length - length + 1, null); + } else if (length < 0 || offset < 0 || + offset > this.length - length) { + throw new IndexOutOfBoundsException(); + } + } + + @DontInline + private void throwOutOfBounds(long offset, long length, boolean isSlice) { + String action = isSlice ? "get slice" : "access an element"; + String msg = String.format("Out of bound access on segment %s; attempting to %s of length %d at offset %d " + + "which is outside the valid range 0 <= offset+length < byteSize (=%d)", + this, action, length, offset, this.length); + throw new IndexOutOfBoundsException(msg); } @Override @@ -429,11 +450,6 @@ public abstract sealed class AbstractMemorySegmentImpl return scope; } - private IndexOutOfBoundsException outOfBoundException(long offset, long length) { - return new IndexOutOfBoundsException(String.format("Out of bound access on segment %s; new offset = %d; new length = %d", - this, offset, length)); - } - static class SegmentSplitter implements Spliterator { AbstractMemorySegmentImpl segment; long elemCount; diff --git a/src/java.base/share/classes/jdk/internal/foreign/CaptureStateUtil.java b/src/java.base/share/classes/jdk/internal/foreign/CaptureStateUtil.java index 2f3ba7d9e05..b3a19340fb5 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/CaptureStateUtil.java +++ b/src/java.base/share/classes/jdk/internal/foreign/CaptureStateUtil.java @@ -38,6 +38,8 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.VarHandle; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Function; @@ -57,7 +59,7 @@ public final class CaptureStateUtil { // of combinators needed to form an adapted method handle. // The function is lazily computed. // - private static final Function SEGMENT_EXTRACTION_HANDLE_CACHE; + private static final Map SEGMENT_EXTRACTION_HANDLE_CACHE; static { final Set inputs = new HashSet<>(); @@ -77,7 +79,7 @@ public final class CaptureStateUtil { } }; - SEGMENT_EXTRACTION_HANDLE_CACHE = StableValue.function(inputs, segmentExtractionHandle); + SEGMENT_EXTRACTION_HANDLE_CACHE = Map.ofLazy(inputs, segmentExtractionHandle); } // A key that holds both the `returnType` and the `stateName` needed to look up a @@ -188,7 +190,10 @@ public final class CaptureStateUtil { final SegmentExtractorKey key = new SegmentExtractorKey(target, stateName); // ((int | long), MemorySegment)(int | long) - final MethodHandle segmentExtractor = SEGMENT_EXTRACTION_HANDLE_CACHE.apply(key); + final MethodHandle segmentExtractor = SEGMENT_EXTRACTION_HANDLE_CACHE.get(key); + if (segmentExtractor == null) { + throw new IllegalArgumentException("Input not allowed: " + key); + } // Make `target` specific adaptations of the basic handle @@ -208,7 +213,7 @@ public final class CaptureStateUtil { // Use an `Arena` for the first argument instead and extract a segment from it. // (C0=Arena, C1-Cn)(int|long) - innerAdapted = MethodHandles.collectArguments(innerAdapted, 0, HANDLES_CACHE.apply(ALLOCATE)); + innerAdapted = MethodHandles.collectArguments(innerAdapted, 0, HANDLES_CACHE.get(ALLOCATE)); // Add an identity function for the result of the cleanup action. // ((int|long))(int|long) @@ -221,7 +226,7 @@ public final class CaptureStateUtil { // cleanup action and invoke `Arena::close` when it is run. The `cleanup` handle // does not have to have all parameters. It can have zero or more. // (Throwable, (int|long), Arena)(int|long) - cleanup = MethodHandles.collectArguments(cleanup, 2, HANDLES_CACHE.apply(ARENA_CLOSE)); + cleanup = MethodHandles.collectArguments(cleanup, 2, HANDLES_CACHE.get(ARENA_CLOSE)); // Combine the `innerAdapted` and `cleanup` action into a try/finally block. // (Arena, C1-Cn)(int|long) @@ -230,7 +235,7 @@ public final class CaptureStateUtil { // Acquire the arena from the global pool. // With this, we finally arrive at the intended method handle: // (C1-Cn)(int|long) - return MethodHandles.collectArguments(tryFinally, 0, HANDLES_CACHE.apply(ACQUIRE_ARENA)); + return MethodHandles.collectArguments(tryFinally, 0, HANDLES_CACHE.get(ACQUIRE_ARENA)); } private static MethodHandle makeSegmentExtractionHandle(SegmentExtractorKey segmentExtractorKey) { @@ -260,15 +265,15 @@ public final class CaptureStateUtil { if (segmentExtractorKey.returnType().equals(int.class)) { // (int, MemorySegment)int return MethodHandles.guardWithTest( - HANDLES_CACHE.apply(NON_NEGATIVE_INT), - HANDLES_CACHE.apply(SUCCESS_INT), - HANDLES_CACHE.apply(ERROR_INT).bindTo(intExtractor)); + HANDLES_CACHE.get(NON_NEGATIVE_INT), + HANDLES_CACHE.get(SUCCESS_INT), + HANDLES_CACHE.get(ERROR_INT).bindTo(intExtractor)); } else { // (long, MemorySegment)long return MethodHandles.guardWithTest( - HANDLES_CACHE.apply(NON_NEGATIVE_LONG), - HANDLES_CACHE.apply(SUCCESS_LONG), - HANDLES_CACHE.apply(ERROR_LONG).bindTo(intExtractor)); + HANDLES_CACHE.get(NON_NEGATIVE_LONG), + HANDLES_CACHE.get(SUCCESS_LONG), + HANDLES_CACHE.get(ERROR_LONG).bindTo(intExtractor)); } } @@ -341,8 +346,8 @@ public final class CaptureStateUtil { } }; - private static final IntFunction HANDLES_CACHE = - StableValue.intFunction(ARENA_CLOSE + 1, UNDERLYING_MAKE_HANDLE); + private static final List HANDLES_CACHE = + List.ofLazy(ARENA_CLOSE + 1, UNDERLYING_MAKE_HANDLE); private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java index 5af4bc37692..ab6b78b73ee 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java @@ -194,7 +194,7 @@ public final class SegmentBulkOperations { @ForceInline public static int contentHash(AbstractMemorySegmentImpl segment, long fromOffset, long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length == 0) { // The state has to be checked explicitly for zero-length segments segment.scope.checkValidState(); diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java index 3edcac2e44c..728ee235547 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java @@ -212,7 +212,9 @@ public class SegmentFactories { allocationBase = allocateMemoryWrapper(allocationSize); result = Utils.alignUp(allocationBase, byteAlignment); } else { - allocationSize = alignedSize; + // always allocate at least 'byteAlignment' bytes, so that malloc is guaranteed to + // return a pointer aligned to that alignment, for cases where byteAlignment > alignedSize + allocationSize = Math.max(alignedSize, byteAlignment); if (shouldReserve) { AbstractMemorySegmentImpl.NIO_ACCESS.reserveMemory(allocationSize, byteSize); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java index bb6cb2d3915..208c6d54aab 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java +++ b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java @@ -145,7 +145,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Byte.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); @@ -179,7 +179,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Short.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); @@ -215,7 +215,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Integer.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/CharacterIteratorWrapper.java b/src/java.base/share/classes/jdk/internal/icu/impl/CharacterIteratorWrapper.java index 79a6264d16d..698f28ea2be 100644 --- a/src/java.base/share/classes/jdk/internal/icu/impl/CharacterIteratorWrapper.java +++ b/src/java.base/share/classes/jdk/internal/icu/impl/CharacterIteratorWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ import jdk.internal.icu.text.UCharacterIterator; * @author ram */ -public class CharacterIteratorWrapper extends UCharacterIterator { +public class CharacterIteratorWrapper extends UCharacterIterator implements Cloneable { private CharacterIterator iterator; @@ -135,7 +135,7 @@ public class CharacterIteratorWrapper extends UCharacterIterator { * Creates a clone of this iterator. Clones the underlying character iterator. * @see UCharacterIterator#clone() */ - public Object clone(){ + public CharacterIteratorWrapper clone(){ try { CharacterIteratorWrapper result = (CharacterIteratorWrapper) super.clone(); result.iterator = (CharacterIterator)this.iterator.clone(); diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/Norm2AllModes.java b/src/java.base/share/classes/jdk/internal/icu/impl/Norm2AllModes.java index 7922bb46829..67c9eff6f34 100644 --- a/src/java.base/share/classes/jdk/internal/icu/impl/Norm2AllModes.java +++ b/src/java.base/share/classes/jdk/internal/icu/impl/Norm2AllModes.java @@ -269,8 +269,8 @@ public final class Norm2AllModes { private Norm2AllModesSingleton(String name) { try { @SuppressWarnings("deprecation") - String DATA_FILE_NAME = "/jdk/internal/icu/impl/data/icudt" + - VersionInfo.ICU_DATA_VERSION_PATH + "/" + name + ".nrm"; + String DATA_FILE_NAME = "/jdk/internal/icu/impl/data/icudata/" + + name + ".nrm"; NormalizerImpl impl=new NormalizerImpl().load(DATA_FILE_NAME); allModes=new Norm2AllModes(impl); } catch (RuntimeException e) { diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/ReplaceableUCharacterIterator.java b/src/java.base/share/classes/jdk/internal/icu/impl/ReplaceableUCharacterIterator.java index cf58f614155..b44a0d7675c 100644 --- a/src/java.base/share/classes/jdk/internal/icu/impl/ReplaceableUCharacterIterator.java +++ b/src/java.base/share/classes/jdk/internal/icu/impl/ReplaceableUCharacterIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -51,7 +51,7 @@ import jdk.internal.icu.text.UCharacterIterator; * * What are first, last, and getBeginIndex doing here?!?!?! */ -public class ReplaceableUCharacterIterator extends UCharacterIterator { +public class ReplaceableUCharacterIterator extends UCharacterIterator implements Cloneable { // public constructor ------------------------------------------------------ @@ -86,9 +86,9 @@ public class ReplaceableUCharacterIterator extends UCharacterIterator { * Replaceableobject * @return copy of this iterator */ - public Object clone(){ + public ReplaceableUCharacterIterator clone(){ try { - return super.clone(); + return (ReplaceableUCharacterIterator) super.clone(); } catch (CloneNotSupportedException e) { return null; // never invoked } diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/UBiDiProps.java b/src/java.base/share/classes/jdk/internal/icu/impl/UBiDiProps.java index 287ac38c87b..e7e1e65c2a0 100644 --- a/src/java.base/share/classes/jdk/internal/icu/impl/UBiDiProps.java +++ b/src/java.base/share/classes/jdk/internal/icu/impl/UBiDiProps.java @@ -201,9 +201,7 @@ public final class UBiDiProps { // data format constants ----------------------------------------------- *** @SuppressWarnings("deprecation") private static final String DATA_FILE_NAME = - "/jdk/internal/icu/impl/data/icudt" + - VersionInfo.ICU_DATA_VERSION_PATH + - "/ubidi.icu"; + "/jdk/internal/icu/impl/data/icudata/ubidi.icu"; /* format "BiDi" */ private static final int FMT=0x42694469; diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/UCharacterProperty.java b/src/java.base/share/classes/jdk/internal/icu/impl/UCharacterProperty.java index f439ae23d0f..073ffe933df 100644 --- a/src/java.base/share/classes/jdk/internal/icu/impl/UCharacterProperty.java +++ b/src/java.base/share/classes/jdk/internal/icu/impl/UCharacterProperty.java @@ -330,9 +330,7 @@ public final class UCharacterProperty */ @SuppressWarnings("deprecation") private static final String DATA_FILE_NAME_ = - "/jdk/internal/icu/impl/data/icudt" + - VersionInfo.ICU_DATA_VERSION_PATH + - "/uprops.icu"; + "/jdk/internal/icu/impl/data/icudata/uprops.icu"; /** * Shift value for lead surrogate to form a supplementary character. diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/nfc.nrm b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/nfc.nrm similarity index 64% rename from src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/nfc.nrm rename to src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/nfc.nrm index 114da46498d..fa1d2917ef7 100644 Binary files a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/nfc.nrm and b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/nfc.nrm differ diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/nfkc.nrm b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/nfkc.nrm similarity index 90% rename from src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/nfkc.nrm rename to src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/nfkc.nrm index 66421d6f29f..c78a9d9cac5 100644 Binary files a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/nfkc.nrm and b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/nfkc.nrm differ diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/ubidi.icu b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/ubidi.icu similarity index 74% rename from src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/ubidi.icu rename to src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/ubidi.icu index a333bde0757..bbd02f5f7dc 100644 Binary files a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/ubidi.icu and b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/ubidi.icu differ diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/uprops.icu b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/uprops.icu new file mode 100644 index 00000000000..b72fcd903e0 Binary files /dev/null and b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudata/uprops.icu differ diff --git a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/uprops.icu b/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/uprops.icu deleted file mode 100644 index ca241674dbb..00000000000 Binary files a/src/java.base/share/classes/jdk/internal/icu/impl/data/icudt76b/uprops.icu and /dev/null differ diff --git a/src/java.base/share/classes/jdk/internal/icu/text/NormalizerBase.java b/src/java.base/share/classes/jdk/internal/icu/text/NormalizerBase.java index f2566d9d419..afa09a3f537 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/NormalizerBase.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/NormalizerBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -420,10 +420,10 @@ public final class NormalizerBase implements Cloneable { * iterator's {@code clone} method does so. * @stable ICU 2.8 */ - public Object clone() { + public NormalizerBase clone() { try { NormalizerBase copy = (NormalizerBase) super.clone(); - copy.text = (UCharacterIterator) text.clone(); + copy.text = text.clone(); copy.mode = mode; copy.options = options; copy.norm2 = norm2; diff --git a/src/java.base/share/classes/jdk/internal/icu/text/UCharacterIterator.java b/src/java.base/share/classes/jdk/internal/icu/text/UCharacterIterator.java index 93978372c3a..24c54795508 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/UCharacterIterator.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/UCharacterIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -310,8 +310,8 @@ public abstract class UCharacterIterator * @return copy of this iterator * @stable ICU 2.4 */ - public Object clone() throws CloneNotSupportedException{ - return super.clone(); + public UCharacterIterator clone() throws CloneNotSupportedException{ + return (UCharacterIterator) super.clone(); } } diff --git a/src/java.base/share/classes/jdk/internal/icu/text/UnicodeSet.java b/src/java.base/share/classes/jdk/internal/icu/text/UnicodeSet.java index 6f5919e016b..0bc68080e83 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/UnicodeSet.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/UnicodeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -293,7 +293,7 @@ import jdk.internal.icu.util.VersionInfo; * @author Alan Liu * @stable ICU 2.0 */ -public class UnicodeSet { +public class UnicodeSet implements Cloneable { private static final int LOW = 0x000000; // LOW <= all valid values. ZERO for codepoints private static final int HIGH = 0x110000; // HIGH > all valid values. 10000 for code units. @@ -385,6 +385,18 @@ public class UnicodeSet { applyPattern(pattern, null); } + /** + * Return a new set that is equivalent to this one. + * @stable ICU 2.0 + */ + @Override + public UnicodeSet clone() { + if (isFrozen()) { + return this; + } + return new UnicodeSet(this); + } + /** * Make this object represent the same set as other. * @param other a UnicodeSet whose value will be diff --git a/src/java.base/share/classes/jdk/internal/icu/util/VersionInfo.java b/src/java.base/share/classes/jdk/internal/icu/util/VersionInfo.java index b7a52b74ae1..fa55b9df5af 100644 --- a/src/java.base/share/classes/jdk/internal/icu/util/VersionInfo.java +++ b/src/java.base/share/classes/jdk/internal/icu/util/VersionInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -54,7 +54,7 @@ public final class VersionInfo * @deprecated This API is ICU internal only. */ @Deprecated - public static final String ICU_DATA_VERSION_PATH = "76b"; + public static final String ICU_DATA_VERSION_PATH = "78b"; // public methods ------------------------------------------------------ diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java index 820dfe90073..a6f4174324e 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java @@ -39,6 +39,7 @@ import java.util.Formatter; import java.util.Locale; import java.util.Objects; import java.util.Optional; +import java.util.function.Supplier; import jdk.internal.access.SharedSecrets; import jdk.internal.util.StaticProperty; @@ -114,24 +115,29 @@ public final class JdkConsoleImpl implements JdkConsole { // check if `System.console()` returns a Console instance and use it if available. Otherwise, // it should call this method to obtain a JdkConsoleImpl. This ensures only one Console // instance exists in the Java runtime. - private static final StableValue> INSTANCE = StableValue.of(); - public static Optional passwordConsole() { - return INSTANCE.orElseSet(() -> { - // If there's already a proper console, throw an exception - if (System.console() != null) { - throw new IllegalStateException("Can’t create a dedicated password " + - "console since a real console already exists"); - } + private static final LazyConstant> PASSWORD_CONSOLE = LazyConstant.of( + new Supplier>() { + @Override + public Optional get() { + if (System.console() != null) { + throw new IllegalStateException("Can’t create a dedicated password " + + "console since a real console already exists"); + } - // If stdin is NOT redirected, return an Optional containing a JdkConsoleImpl - // instance, otherwise an empty Optional. - return SharedSecrets.getJavaIOAccess().isStdinTty() ? - Optional.of( - new JdkConsoleImpl( - Charset.forName(StaticProperty.stdinEncoding(), UTF_8.INSTANCE), - Charset.forName(StaticProperty.stdoutEncoding(), UTF_8.INSTANCE))) : - Optional.empty(); - }); + // If stdin is NOT redirected, return an Optional containing a JdkConsoleImpl + // instance, otherwise an empty Optional. + return SharedSecrets.getJavaIOAccess().isStdinTty() ? + Optional.of( + new JdkConsoleImpl( + Charset.forName(StaticProperty.stdinEncoding(), UTF_8.INSTANCE), + Charset.forName(StaticProperty.stdoutEncoding(), UTF_8.INSTANCE))) : + Optional.empty(); + } + } + ); + + public static Optional passwordConsole() { + return PASSWORD_CONSOLE.get(); } // Dedicated entry for sun.security.util.Password when stdout is redirected. diff --git a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java index 6b8cda6aa1a..5942cefa2a1 100644 --- a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java @@ -85,9 +85,10 @@ public @interface PreviewFeature { //--- @JEP(number=525, title="Structured Concurrency", status="Sixth Preview") STRUCTURED_CONCURRENCY, - @JEP(number = 502, title = "Stable Values", status = "Preview") - STABLE_VALUES, - @JEP(number=470, title="PEM Encodings of Cryptographic Objects", status="Preview") + @JEP(number = 526, title = "Lazy Constants", status = "Second Preview") + LAZY_CONSTANTS, + @JEP(number=524, title="PEM Encodings of Cryptographic Objects", + status="Second Preview") PEM_API, LANGUAGE_MODEL, /** diff --git a/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java b/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java index c06c62488db..6807928b2c2 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java +++ b/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java @@ -317,13 +317,12 @@ public class BasicImageReader implements AutoCloseable { } public String[] getEntryNames() { - int[] attributeOffsets = new int[offsets.capacity()]; - offsets.get(attributeOffsets); - return IntStream.of(attributeOffsets) - .filter(o -> o != 0) - .mapToObj(o -> ImageLocation.readFrom(this, o).getFullName()) - .sorted() - .toArray(String[]::new); + return IntStream.range(0, offsets.capacity()) + .map(offsets::get) + .filter(o -> o != 0) + .mapToObj(o -> ImageLocation.readFrom(this, o).getFullName()) + .sorted() + .toArray(String[]::new); } ImageLocation getLocation(int offset) { diff --git a/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template b/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template new file mode 100644 index 00000000000..24a183c8da0 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2025, 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 jdk.internal.lang; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static java.util.Map.entry; + +/** + * Utility class that handles Unicode case folding properties defined in + * CasingFolding.txt, including 1:M full case folding. + */ +public final class CaseFolding { + + private CaseFolding() {} + + /** + * Tests whether the specified code point has a folding mapping entry defined. + * + * @param cp + * the Unicode code point to test + * @return {@code true} if the given code point has a case folding mapping entry + * defined in (@code caseFoldingMap}, {@code false} otherwise + */ + public static boolean isDefined(int cp) { + return getDefined(cp) != -1; + } + + /** + * Returns the case-folded form of the specified code point according + * to the Unicode case folding mappings. + *

    + * If the code point has no case folding mapping defined, this method returns + * the original code point. + * + * Possible combinations of the returning case-folding form as a long value + * + * +---+---------+--------+---------+--------+--------+ + * | 1:1 mapping | 0000 | 0000 | 000x | xxxx | 0041 => 0061 or 1E921 => 1E943 + * +---+---------+--------+---------+--------+--------+ + * | 1:2 mapping | 0002 | 0000 | xxxx | xxxx | FB02 => 0066 006C + * +---+---------+--------+---------+--------+--------+ + * | 1:3 mapping | 0003 | xxxx | xxxx | xxxx | FB03 => 0066 0066 0069 + * +---+---------+--------+---------+--------+--------+ + * + * @param cp + * the Unicode code point to fold + * @return a long value representing the case-folded form of the input + * code point, encoded as TBD + */ + public static long fold(int cp) { + var fold = getDefined(cp); + return fold == -1 ? cp : fold; + } + + public static boolean isSingleCodePoint(long fold) { + return (fold >> 48) == 0; + } + + /** + * Returns an expansion set to "close" a given regex Unicode character class range for case-sensitive + * matching, according to the + * Simple Loose Matches + * rule defined in Unicode Technical Standard #18: Unicode Regular Expressions. + *

    + * To conform with Level 1 of UTS #18, specifically RL1.5: Simple Loose Matches, simple case folding must + * be applied to literals and (optionally) to character classes. When applied to character classes, each + * character class is expected to be closed under simple case folding. See the standard for the + * detailed explanation and example of "closed". + *

    + * RL1.5 states: To meet this requirement, an implementation that supports case-sensitive matching should + *

      + *
    1. Provide at least the simple, default Unicode case-insensitive matching, and
    2. + *
    3. Specify which character properties or constructs are closed under the matching.
    4. + *
    + *

    + * In the {@code Pattern} implementation, 5 types of constructs maybe case-sensitive when matching: + * back-refs, string slice (sequences), single, family(char-property) and class range. Single and + * family may appears independently or within a class. + *

    + * For loose/case-insensitive matching, the back-refs, slices and singles apply {@code toUpperCase} and + * {@code toLowerCase} to both the pattern and the input string. This effectively 'close' the class for + * matching. + *

    + * The family/char-properties are not "closed" and should remain unchanged. This is acceptable per RL1.5, + * if their behavior is clearly specified. + *

    + * This method addresses that requirement for the "range" construct within in character class by computing + * the additional characters that should be included to close the range under simple case folding: + *

    + * For each character in the input range {@code [start, end]} (inclusive), if the character has a simple + * case folding mapping in Unicode's CaseFolding.txt, the mapping is not a round-trip map, and the mapped + * character is not already in the range, then that mapped character (typically lowercase) is added to + * the expansion set. + *

    + * This allows regex character class "range" implementation to use the returned expansion set to support + * additional case-insensitive matching, without duplicating characters already covered by the existing + * regex range implementation. The expectation is the matching is done using both the uppercase and + * lowercase forms of the input character, for example + * + *

    {@code
    +    *
    +    *     ch -> inRange(lower, Character.toUpperCase(ch), upper) ||
    +    *           inRange(lower, Character.toLower(ch), upper) ||
    +    *           additionalClosingCharacters.contains(Character.toUpperCase(ch)) ||
    +    *           additionalClosingCharacters.contains(Character.toUpperCase(ch))
    +    * }
    + * + * @param start the starting code point of the character range + * @param end the ending code point of the character range + * @return a {@code int[]} containing the all simple case equivalents of characters in the range, excluding + * those already in the range + * @spec https://www.unicode.org/reports/tr18/#Simple_Loose_Matches + */ + public static int[] getClassRangeClosingCharacters(int start, int end) { + int[] expanded = new int[expanded_case_cps.length]; + int off = 0; + for (int cp : expanded_case_cps) { + if (cp >= start && cp <= end) { + int folding = expanded_case_map.get(cp); + if (folding < start || folding > end) { + expanded[off++] = folding; + } + } + } + return Arrays.copyOf(expanded, off); + } + + private static final Map expanded_case_map = Map.ofEntries( +%%%Expanded_Case_Map_Entries + ); + + private static final int[] expanded_case_cps = expanded_case_map.keySet() + .stream() + .mapToInt(Integer::intValue) + .toArray(); + + private static final int HASH_CP = 0; + private static final int HASH_INDEX = 1; + private static final int HASH_NEXT = 2; + + private static int[][] hashKeys(int[] keys) { + var hashes = new int[keys.length << 1][3]; // cp + hash + next + var off = keys.length; + for (int i = 0; i < keys.length; i++) { + var cp = keys[i]; + var hash = cp % keys.length; + while (hashes[hash][HASH_CP] != 0) { + var next = hashes[hash][HASH_NEXT]; + if (next == 0) { + hashes[hash][HASH_NEXT] = off; + hash = off++; + break; + } else { + hash = next; + } + } + hashes[hash][HASH_CP] = cp; + hashes[hash][HASH_INDEX] = i; + } + return Arrays.copyOf(hashes, off); + } + + private static long getDefined(int cp) { + var hashes = CASE_FOLDING_HASHES; + var length = CASE_FOLDING_CPS.length; // hashed based on total defined. + var hash = cp % length; + while (hashes[hash][HASH_CP] != cp) { + var next = hashes[hash][HASH_NEXT]; + if (next == 0) { + return -1; // hash miss + } + hash = next; + } + var index = hashes[hash][HASH_INDEX]; + return CASE_FOLDING_VALUES[index]; + } + +%%%Entries + + private static final int[][] CASE_FOLDING_HASHES = hashKeys(CASE_FOLDING_CPS); +} diff --git a/src/java.base/share/classes/jdk/internal/lang/LazyConstantImpl.java b/src/java.base/share/classes/jdk/internal/lang/LazyConstantImpl.java new file mode 100644 index 00000000000..59d0174c4c9 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/lang/LazyConstantImpl.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2025, 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 jdk.internal.lang; + +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.AOTSafeClassInitializer; +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; + +import java.util.Objects; +import java.util.function.Supplier; + +/** + * The sole implementation of the LazyConstant interface. + * + * @param type of the constant + * @implNote This implementation can be used early in the boot sequence as it does not + * rely on reflection, MethodHandles, Streams etc. + */ +@AOTSafeClassInitializer +public final class LazyConstantImpl implements LazyConstant { + + // Unsafe allows `LazyConstant` instances to be used early in the boot sequence + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + // Unsafe offset for access of the `constant` field + private static final long CONSTANT_OFFSET = + UNSAFE.objectFieldOffset(LazyConstantImpl.class, "constant"); + + // Generally, fields annotated with `@Stable` are accessed by the JVM using special + // memory semantics rules (see `parse.hpp` and `parse(1|2|3).cpp`). + // + // This field is used reflectively via Unsafe using explicit memory semantics. + // + // | Value | Meaning | + // | --------------- | -------------- | + // | `null` | Unset | + // | `other` | Set to `other` | + // + @Stable + private T constant; + + // Underlying computing function to be used to compute the `constant` field. + // The field needs to be `volatile` as a lazy constant can be + // created by one thread and computed by another thread. + // After the function is successfully invoked, the field is set to + // `null` to allow the function to be collected. + @Stable + private volatile Supplier computingFunction; + + private LazyConstantImpl(Supplier computingFunction) { + this.computingFunction = computingFunction; + } + + @ForceInline + @Override + public T get() { + final T t = getAcquire(); + return (t != null) ? t : getSlowPath(); + } + + private T getSlowPath() { + preventReentry(); + synchronized (this) { + T t = getAcquire(); + if (t == null) { + t = computingFunction.get(); + Objects.requireNonNull(t); + setRelease(t); + // Allow the underlying supplier to be collected after successful use + computingFunction = null; + } + return t; + } + } + + @ForceInline + @Override + public T orElse(T other) { + final T t = getAcquire(); + return (t == null) ? other : t; + } + + @ForceInline + @Override + public boolean isInitialized() { + return getAcquire() != null; + } + + @Override + public String toString() { + return super.toString() + "[" + toStringSuffix() + "]"; + } + + private String toStringSuffix() { + final T t = getAcquire(); + if (t == this) { + return "(this LazyConstant)"; + } else if (t != null) { + return t.toString(); + } + // Volatile read + final Supplier cf = computingFunction; + // There could be a race here + if (cf != null) { + return "computing function=" + computingFunction.toString(); + } + // As we know `computingFunction` is `null` via a volatile read, we + // can now be sure that this lazy constant is initialized + return getAcquire().toString(); + } + + + // Discussion on the memory semantics used. + // ---------------------------------------- + // Using acquire/release semantics on the `constant` field is the cheapest way to + // establish a happens-before (HB) relation between load and store operations. Every + // implementation of a method defined in the interface `LazyConstant` except + // `equals()` starts with a load of the `constant` field using acquire semantics. + // + // If the underlying supplier was guaranteed to always create a new object, + // a fence after creation and subsequent plain loads would suffice to ensure + // new objects' state are always correctly observed. However, no such restriction is + // imposed on the underlying supplier. Hence, the docs state there should be an + // HB relation meaning we will have to pay a price (on certain platforms) on every + // `get()` operation that is not constant-folded. + + @SuppressWarnings("unchecked") + @ForceInline + private T getAcquire() { + return (T) UNSAFE.getReferenceAcquire(this, CONSTANT_OFFSET); + } + + private void setRelease(T newValue) { + UNSAFE.putReferenceRelease(this, CONSTANT_OFFSET, newValue); + } + + private void preventReentry() { + if (Thread.holdsLock(this)) { + throw new IllegalStateException("Recursive invocation of a LazyConstant's computing function: " + computingFunction); + } + } + + // Factory + + public static LazyConstantImpl ofLazy(Supplier computingFunction) { + return new LazyConstantImpl<>(computingFunction); + } + +} diff --git a/src/java.base/share/classes/jdk/internal/lang/stable/StableEnumFunction.java b/src/java.base/share/classes/jdk/internal/lang/stable/StableEnumFunction.java deleted file mode 100644 index d6893438be5..00000000000 --- a/src/java.base/share/classes/jdk/internal/lang/stable/StableEnumFunction.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.internal.lang.stable; - -import jdk.internal.util.ImmutableBitSetPredicate; -import jdk.internal.vm.annotation.ForceInline; -import jdk.internal.vm.annotation.Stable; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Collection; -import java.util.EnumSet; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.function.IntPredicate; -import java.util.function.Supplier; - -/** - * Optimized implementation of a stable Function with enums as keys. - * - * @implNote This implementation can be used early in the boot sequence as it does not - * rely on reflection, MethodHandles, Streams etc. - * - * @param enumType the class type of the Enum - * @param firstOrdinal the lowest ordinal used - * @param member an int predicate that can be used to test if an enum is a member - * of the valid inputs (as there might be "holes") - * @param delegates a delegate array of inputs to StableValue mappings - * @param original the original Function - * @param the type of the input to the function - * @param the type of the result of the function - */ -public record StableEnumFunction, R>(Class enumType, - int firstOrdinal, - IntPredicate member, - @Stable StableValueImpl[] delegates, - Function original) implements Function { - @ForceInline - @Override - public R apply(E value) { - if (!member.test(value.ordinal())) { // Implicit null-check of value - throw new IllegalArgumentException("Input not allowed: " + value); - } - final int index = value.ordinal() - firstOrdinal; - // Since we did the member.test above, we know the index is in bounds - return delegates[index].orElseSet(new Supplier() { - @Override public R get() { return original.apply(value); }}); - - } - - @Override - public int hashCode() { - return System.identityHashCode(this); - } - - @Override - public boolean equals(Object obj) { - return obj == this; - } - - @Override - public String toString() { - final Collection>> entries = new ArrayList<>(delegates.length); - final E[] enumElements = enumType.getEnumConstants(); - int ordinal = firstOrdinal; - for (int i = 0; i < delegates.length; i++, ordinal++) { - if (member.test(ordinal)) { - entries.add(new AbstractMap.SimpleImmutableEntry<>(enumElements[ordinal], delegates[i])); - } - } - return StableUtil.renderMappings(this, "StableFunction", entries, true); - } - - @SuppressWarnings("unchecked") - public static , R> Function of(Set inputs, - Function original) { - // The input set is not empty - final Class enumType = ((E) inputs.iterator().next()).getDeclaringClass(); - final BitSet bitSet = new BitSet(enumType.getEnumConstants().length); - int min = Integer.MAX_VALUE; - int max = Integer.MIN_VALUE; - for (T t : inputs) { - final int ordinal = ((E) t).ordinal(); - min = Math.min(min, ordinal); - max = Math.max(max, ordinal); - bitSet.set(ordinal); - } - final int size = max - min + 1; - final IntPredicate member = ImmutableBitSetPredicate.of(bitSet); - return (Function) new StableEnumFunction(enumType, min, member, StableUtil.array(size), (Function) original); - } - -} diff --git a/src/java.base/share/classes/jdk/internal/lang/stable/StableFunction.java b/src/java.base/share/classes/jdk/internal/lang/stable/StableFunction.java deleted file mode 100644 index e36b4e9b25a..00000000000 --- a/src/java.base/share/classes/jdk/internal/lang/stable/StableFunction.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.internal.lang.stable; - -import jdk.internal.vm.annotation.ForceInline; - -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Supplier; - -// Note: It would be possible to just use `StableMap::get` with some additional logic -// instead of this class but explicitly providing a class like this provides better -// debug capability, exception handling, and may provide better performance. -/** - * Implementation of a stable Function. - * - * @implNote This implementation can be used early in the boot sequence as it does not - * rely on reflection, MethodHandles, Streams etc. - * - * @param values a delegate map of inputs to StableValue mappings - * @param original the original Function - * @param the type of the input to the function - * @param the type of the result of the function - */ -public record StableFunction(Map> values, - Function original) implements Function { - - @ForceInline - @Override - public R apply(T value) { - final StableValueImpl stable = values.get(value); - if (stable == null) { - throw new IllegalArgumentException("Input not allowed: " + value); - } - return stable.orElseSet(new Supplier() { - @Override public R get() { return original.apply(value); }}); - } - - @Override - public int hashCode() { - return System.identityHashCode(this); - } - - @Override - public boolean equals(Object obj) { - return obj == this; - } - - @Override - public String toString() { - return StableUtil.renderMappings(this, "StableFunction", values.entrySet(), true); - } - - public static StableFunction of(Set inputs, - Function original) { - return new StableFunction<>(StableUtil.map(inputs), original); - } - -} diff --git a/src/java.base/share/classes/jdk/internal/lang/stable/StableIntFunction.java b/src/java.base/share/classes/jdk/internal/lang/stable/StableIntFunction.java deleted file mode 100644 index a921a4de87b..00000000000 --- a/src/java.base/share/classes/jdk/internal/lang/stable/StableIntFunction.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.internal.lang.stable; - -import jdk.internal.vm.annotation.ForceInline; -import jdk.internal.vm.annotation.Stable; - -import java.util.function.IntFunction; -import java.util.function.Supplier; - -/** - * Implementation of a stable IntFunction. - *

    - * For performance reasons (~10%), we are not delegating to a StableList but are using - * the more primitive functions in StableValueUtil that are shared with StableList/StableValueImpl. - * - * @implNote This implementation can be used early in the boot sequence as it does not - * rely on reflection, MethodHandles, Streams etc. - * - * @param the return type - */ -public record StableIntFunction(@Stable StableValueImpl[] delegates, - IntFunction original) implements IntFunction { - - @ForceInline - @Override - public R apply(int index) { - final StableValueImpl delegate; - try { - delegate = delegates[index]; - } catch (ArrayIndexOutOfBoundsException ioob) { - throw new IllegalArgumentException("Input not allowed: " + index, ioob); - } - return delegate.orElseSet(new Supplier() { - @Override public R get() { return original.apply(index); }}); - } - - @Override - public int hashCode() { - return System.identityHashCode(this); - } - - @Override - public boolean equals(Object obj) { - return obj == this; - } - - @Override - public String toString() { - return StableUtil.renderElements(this, "StableIntFunction", delegates); - } - - public static StableIntFunction of(int size, IntFunction original) { - return new StableIntFunction<>(StableUtil.array(size), original); - } - -} diff --git a/src/java.base/share/classes/jdk/internal/lang/stable/StableUtil.java b/src/java.base/share/classes/jdk/internal/lang/stable/StableUtil.java deleted file mode 100644 index 74104ddbb49..00000000000 --- a/src/java.base/share/classes/jdk/internal/lang/stable/StableUtil.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.internal.lang.stable; - -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.StringJoiner; - -public final class StableUtil { - - private StableUtil() {} - - public static String renderElements(Object self, - String selfName, - StableValueImpl[] delegates) { - return renderElements(self, selfName, delegates, 0, delegates.length); - } - - public static String renderElements(Object self, - String selfName, - StableValueImpl[] delegates, - int offset, - int length) { - final StringJoiner sj = new StringJoiner(", ", "[", "]"); - for (int i = 0; i < length; i++) { - final Object value = delegates[i + offset].wrappedContentsAcquire(); - if (value == self) { - sj.add("(this " + selfName + ")"); - } else { - sj.add(StableValueImpl.renderWrapped(value)); - } - } - return sj.toString(); - } - - public static String renderMappings(Object self, - String selfName, - Iterable>> delegates, - boolean curly) { - final StringJoiner sj = new StringJoiner(", ", curly ? "{" : "[", curly ? "}" : "]"); - for (var e : delegates) { - final Object value = e.getValue().wrappedContentsAcquire(); - final String valueString; - if (value == self) { - valueString = "(this " + selfName + ")"; - } else { - valueString = StableValueImpl.renderWrapped(value); - } - sj.add(e.getKey() + "=" + valueString); - } - return sj.toString(); - } - - public static StableValueImpl[] array(int size) { - assertSizeNonNegative(size); - @SuppressWarnings("unchecked") - final var stableValues = (StableValueImpl[]) new StableValueImpl[size]; - for (int i = 0; i < size; i++) { - stableValues[i] = StableValueImpl.of(); - } - return stableValues; - } - - public static Map> map(Set keys) { - Objects.requireNonNull(keys); - @SuppressWarnings("unchecked") - final var entries = (Map.Entry>[]) new Map.Entry[keys.size()]; - int i = 0; - for (K key : keys) { - entries[i++] = Map.entry(key, StableValueImpl.of()); - } - return Map.ofEntries(entries); - } - - public static void assertSizeNonNegative(int size) { - if (size < 0) { - throw new IllegalArgumentException("size can not be negative: " + size); - } - } - -} diff --git a/src/java.base/share/classes/jdk/internal/lang/stable/StableValueImpl.java b/src/java.base/share/classes/jdk/internal/lang/stable/StableValueImpl.java deleted file mode 100644 index 1413fd7446e..00000000000 --- a/src/java.base/share/classes/jdk/internal/lang/stable/StableValueImpl.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.internal.lang.stable; - -import jdk.internal.misc.Unsafe; -import jdk.internal.vm.annotation.DontInline; -import jdk.internal.vm.annotation.ForceInline; -import jdk.internal.vm.annotation.Stable; - -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.function.Supplier; - -/** - * The implementation of StableValue. - * - * @implNote This implementation can be used early in the boot sequence as it does not - * rely on reflection, MethodHandles, Streams etc. - * - * @param type of the contents - */ -public final class StableValueImpl implements StableValue { - - static final String UNSET_LABEL = ".unset"; - - // Unsafe allows StableValue to be used early in the boot sequence - static final Unsafe UNSAFE = Unsafe.getUnsafe(); - - // Unsafe offsets for direct field access - - private static final long CONTENTS_OFFSET = - UNSAFE.objectFieldOffset(StableValueImpl.class, "contents"); - - // Used to indicate a holder value is `null` (see field `contents` below) - private static final Object NULL_SENTINEL = new Object(); - - // Generally, fields annotated with `@Stable` are accessed by the JVM using special - // memory semantics rules (see `parse.hpp` and `parse(1|2|3).cpp`). - // - // This field is used directly and reflectively via Unsafe using explicit memory semantics. - // - // | Value | Meaning | - // | -------------- | ------------ | - // | null | Unset | - // | NULL_SENTINEL | Set(null) | - // | other | Set(other) | - // - @Stable - private Object contents; - - // Only allow creation via the factory `StableValueImpl::newInstance` - private StableValueImpl() {} - - @ForceInline - @Override - public boolean trySet(T contents) { - if (wrappedContentsAcquire() != null) { - return false; - } - // Prevent reentry via an orElseSet(supplier) - preventReentry(); - // Mutual exclusion is required here as `orElseSet` might also - // attempt to modify `this.contents` - synchronized (this) { - return wrapAndSet(contents); - } - } - - @ForceInline - @Override - public void setOrThrow(T contents) { - if (!trySet(contents)) { - // Neither the set contents nor the provided contents is revealed in the - // exception message as it might be sensitive. - throw new IllegalStateException("The contents is already set"); - } - } - - @ForceInline - @Override - public T orElseThrow() { - final Object t = wrappedContentsAcquire(); - if (t == null) { - throw new NoSuchElementException("No contents set"); - } - return unwrap(t); - } - - @ForceInline - @Override - public T orElse(T other) { - final Object t = wrappedContentsAcquire(); - return (t == null) ? other : unwrap(t); - } - - @ForceInline - @Override - public boolean isSet() { - return wrappedContentsAcquire() != null; - } - - @ForceInline - @Override - public T orElseSet(Supplier supplier) { - Objects.requireNonNull(supplier); - final Object t = wrappedContentsAcquire(); - return (t == null) ? orElseSetSlowPath(supplier) : unwrap(t); - } - - @DontInline - private T orElseSetSlowPath(Supplier supplier) { - preventReentry(); - synchronized (this) { - final Object t = contents; // Plain semantics suffice here - if (t == null) { - final T newValue = supplier.get(); - // The mutex is not reentrant so we know newValue should be returned - wrapAndSet(newValue); - return newValue; - } - return unwrap(t); - } - } - - // The methods equals() and hashCode() should be based on identity (defaults from Object) - - @Override - public String toString() { - final Object t = wrappedContentsAcquire(); - return t == this - ? "(this StableValue)" - : renderWrapped(t); - } - - // Internal methods shared with other internal classes - - @ForceInline - public Object wrappedContentsAcquire() { - return UNSAFE.getReferenceAcquire(this, CONTENTS_OFFSET); - } - - static String renderWrapped(Object t) { - return (t == null) ? UNSET_LABEL : Objects.toString(unwrap(t)); - } - - // Private methods - - // This method is not annotated with @ForceInline as it is always called - // in a slow path. - private void preventReentry() { - if (Thread.holdsLock(this)) { - throw new IllegalStateException("Recursive initialization of a stable value is illegal"); - } - } - - /** - * Wraps the provided {@code newValue} and tries to set the contents. - *

    - * This method ensures the {@link Stable} field is written to at most once. - * - * @param newValue to wrap and set - * @return if the contents was set - */ - @ForceInline - private boolean wrapAndSet(T newValue) { - assert Thread.holdsLock(this); - // We know we hold the monitor here so plain semantic is enough - if (contents == null) { - UNSAFE.putReferenceRelease(this, CONTENTS_OFFSET, wrap(newValue)); - return true; - } - return false; - } - - - // Wraps `null` values into a sentinel value - @ForceInline - private static Object wrap(Object t) { - return (t == null) ? NULL_SENTINEL : t; - } - - // Unwraps null sentinel values into `null` - @SuppressWarnings("unchecked") - @ForceInline - private static T unwrap(Object t) { - return t != NULL_SENTINEL ? (T) t : null; - } - - // Factory - - public static StableValueImpl of() { - return new StableValueImpl<>(); - } - -} diff --git a/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template b/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template new file mode 100644 index 00000000000..2d46f8f0e60 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template @@ -0,0 +1 @@ +@@COMPANY_NAME@@-@@VERSION_STRING@@-@@VERSION_DATE@@ diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java index 45cddc9fb6f..4dfc740024e 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java @@ -452,9 +452,12 @@ public final class ModuleBootstrap { addExtraReads(bootLayer); addExtraExportsAndOpens(bootLayer); - // add enable native access + // enable native access to modules specified to --enable-native-access addEnableNativeAccess(bootLayer); + // allow final mutation by modules specified to --enable-final-field-mutation + addEnableFinalFieldMutation(bootLayer); + Counters.add("jdk.module.boot.7.adjustModulesTime"); // Step 8: CDS dump phase @@ -721,7 +724,6 @@ public final class ModuleBootstrap { * additional packages specified on the command-line. */ private static void addExtraExportsAndOpens(ModuleLayer bootLayer) { - // --add-exports String prefix = "jdk.module.addexports."; Map> extraExports = decode(prefix); @@ -729,14 +731,12 @@ public final class ModuleBootstrap { addExtraExportsOrOpens(bootLayer, extraExports, false); } - // --add-opens prefix = "jdk.module.addopens."; Map> extraOpens = decode(prefix); if (!extraOpens.isEmpty()) { addExtraExportsOrOpens(bootLayer, extraOpens, true); } - } private static void addExtraExportsOrOpens(ModuleLayer bootLayer, @@ -807,6 +807,7 @@ public final class ModuleBootstrap { private static final Set USER_NATIVE_ACCESS_MODULES; private static final Set JDK_NATIVE_ACCESS_MODULES; private static final IllegalNativeAccess ILLEGAL_NATIVE_ACCESS; + private static final IllegalFinalFieldMutation ILLEGAL_FINAL_FIELD_MUTATION; public enum IllegalNativeAccess { ALLOW, @@ -814,14 +815,26 @@ public final class ModuleBootstrap { DENY } + public enum IllegalFinalFieldMutation { + ALLOW, + WARN, + DEBUG, + DENY + } + + static { + ILLEGAL_NATIVE_ACCESS = decodeIllegalNativeAccess(); + USER_NATIVE_ACCESS_MODULES = decodeEnableNativeAccess(); + JDK_NATIVE_ACCESS_MODULES = ModuleLoaderMap.nativeAccessModules(); + ILLEGAL_FINAL_FIELD_MUTATION = decodeIllegalFinalFieldMutation(); + } + public static IllegalNativeAccess illegalNativeAccess() { return ILLEGAL_NATIVE_ACCESS; } - static { - ILLEGAL_NATIVE_ACCESS = addIllegalNativeAccess(); - USER_NATIVE_ACCESS_MODULES = decodeEnableNativeAccess(); - JDK_NATIVE_ACCESS_MODULES = ModuleLoaderMap.nativeAccessModules(); + public static IllegalFinalFieldMutation illegalFinalFieldMutation() { + return ILLEGAL_FINAL_FIELD_MUTATION; } /** @@ -881,7 +894,7 @@ public final class ModuleBootstrap { /** * Process the --illegal-native-access option (and its default). */ - private static IllegalNativeAccess addIllegalNativeAccess() { + private static IllegalNativeAccess decodeIllegalNativeAccess() { String value = getAndRemoveProperty("jdk.module.illegal.native.access"); // don't use a switch: bootstrapping issues! if (value == null) { @@ -899,6 +912,71 @@ public final class ModuleBootstrap { } } + /** + * Process the --illegal-final-field-mutation option. + */ + private static IllegalFinalFieldMutation decodeIllegalFinalFieldMutation() { + String value = getAndRemoveProperty("jdk.module.illegal.final.field.mutation"); + if (value == null) { + return IllegalFinalFieldMutation.WARN; // default + } else if (value.equals("allow")) { + return IllegalFinalFieldMutation.ALLOW; + } else if (value.equals("warn")) { + return IllegalFinalFieldMutation.WARN; + } else if (value.equals("debug")) { + return IllegalFinalFieldMutation.DEBUG; + } else if (value.equals("deny")) { + return IllegalFinalFieldMutation.DENY; + } else { + fail("Value specified to --illegal-final-field-mutation not recognized:" + + " '" + value + "'"); + return null; + } + } + + /** + * Process the modules specified to --enable-final-field-mutation and grant the + * capability to mutate finals to specified named modules or all unnamed modules. + */ + private static void addEnableFinalFieldMutation(ModuleLayer bootLayer) { + for (String name : decodeEnableFinalFieldMutation()) { + if (name.equals("ALL-UNNAMED")) { + JLA.addEnableFinalMutationToAllUnnamed(); + } else { + Module m = bootLayer.findModule(name).orElse(null); + if (m != null) { + JLA.tryEnableFinalMutation(m); + } else { + warnUnknownModule("--enable-final-field-mutation", name); + } + } + } + } + + /** + * Returns the set of module names specified by --enable-final-field-mutation options. + */ + private static Set decodeEnableFinalFieldMutation() { + String prefix = "jdk.module.enable.final.field.mutation."; + int index = 0; + // the system property is removed after decoding + String value = getAndRemoveProperty(prefix + index); + Set modules = new HashSet<>(); + if (value == null) { + return modules; + } + while (value != null) { + for (String s : value.split(",")) { + if (!s.isEmpty()) { + modules.add(s); + } + } + index++; + value = getAndRemoveProperty(prefix + index); + } + return modules; + } + /** * Decodes the values of --add-reads, -add-exports, --add-opens or * --patch-modules options that are encoded in system properties. diff --git a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java index d24cc77600c..eb3f25ceca7 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java +++ b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java @@ -225,6 +225,7 @@ public final class ModulePatcher { private final ModuleReference mref; private final URL delegateCodeSourceURL; private volatile ModuleReader delegate; + private volatile boolean closed; /** * Creates the ModuleReader to reads resources in a patched module. @@ -291,6 +292,15 @@ public final class ModulePatcher { return r; } + /** + * Throws an IOException if the ModuleReader is closed. + */ + private void ensureOpen() throws IOException { + if (closed) { + throw new IOException("ModuleReader is closed"); + } + } + /** * Finds a resources in the patch locations. Returns null if not found * or the name is "module-info.class" as that cannot be overridden. @@ -310,7 +320,7 @@ public final class ModulePatcher { * Finds a resource of the given name in the patched module. */ public Resource findResource(String name) throws IOException { - + assert !closed : "module reader is closed"; // patch locations Resource r = findResourceInPatch(name); if (r != null) @@ -354,6 +364,7 @@ public final class ModulePatcher { @Override public Optional find(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { URI uri = URI.create(r.getURL().toString()); @@ -365,6 +376,7 @@ public final class ModulePatcher { @Override public Optional open(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { return Optional.of(r.getInputStream()); @@ -375,6 +387,7 @@ public final class ModulePatcher { @Override public Optional read(String name) throws IOException { + ensureOpen(); Resource r = findResourceInPatch(name); if (r != null) { ByteBuffer bb = r.getByteBuffer(); @@ -398,6 +411,7 @@ public final class ModulePatcher { @Override public Stream list() throws IOException { + ensureOpen(); Stream s = delegate().list(); for (ResourceFinder finder : finders) { s = Stream.concat(s, finder.list()); @@ -407,6 +421,10 @@ public final class ModulePatcher { @Override public void close() throws IOException { + if (closed) { + return; + } + closed = true; closeAll(finders); delegate().close(); } diff --git a/src/java.base/share/classes/jdk/internal/module/Modules.java b/src/java.base/share/classes/jdk/internal/module/Modules.java index 3c3d148e196..760b3ba9a08 100644 --- a/src/java.base/share/classes/jdk/internal/module/Modules.java +++ b/src/java.base/share/classes/jdk/internal/module/Modules.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -139,6 +139,45 @@ public class Modules { JLA.addEnableNativeAccessToAllUnnamed(); } + /** + * Enable code in all unnamed modules to mutate final instance fields. + */ + public static void addEnableFinalMutationToAllUnnamed() { + JLA.addEnableFinalMutationToAllUnnamed(); + } + + /** + * Enable code in a given module to mutate final instance fields. + */ + public static boolean tryEnableFinalMutation(Module m) { + return JLA.tryEnableFinalMutation(m); + } + + /** + * Return true if code in a given module is allowed to mutate final instance fields. + */ + public static boolean isFinalMutationEnabled(Module m) { + return JLA.isFinalMutationEnabled(m); + } + + /** + * Return true if a given module has statically exported the given package to a given + * other module. "statically exported" means the module declaration, --add-exports on + * the command line, or Add-Exports in the main manifest of an executable JAR. + */ + public static boolean isStaticallyExported(Module m, String pn, Module other) { + return JLA.isStaticallyExported(m, pn, other); + } + + /** + * Return true if a given module has statically opened the given package to a given + * other module. "statically open" means the module declaration, --add-opens on the + * command line, or Add-Opens in the main manifest of an executable JAR. + */ + public static boolean isStaticallyOpened(Module m, String pn, Module other) { + return JLA.isStaticallyOpened(m, pn, other); + } + /** * Updates module m to use a service. * Same as m2.addUses(service) but without a caller check. diff --git a/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java b/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java index 5cf0c999fb9..15b3c450d03 100644 --- a/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java +++ b/src/java.base/share/classes/jdk/internal/net/quic/QuicTLSContext.java @@ -74,7 +74,7 @@ public final class QuicTLSContext { /** * {@return {@code true} if protocols of the given {@code parameters} support QUIC TLS, {@code false} otherwise} */ - public static boolean isQuicCompatible(SSLParameters parameters) { + private static boolean isQuicCompatible(SSLParameters parameters) { String[] protocols = parameters.getProtocols(); return protocols != null && Arrays.asList(protocols).contains("TLSv1.3"); } diff --git a/src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java b/src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java index bbb0b6738d1..4d9d560fded 100644 --- a/src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java +++ b/src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java @@ -49,24 +49,23 @@ public final class DateTimeHelper { * Requires extra capacity of 10 to avoid StringBuilder reallocation. */ public static void formatTo(StringBuilder buf, LocalDate date) { - int year = date.getYear(), - month = date.getMonthValue(), - day = date.getDayOfMonth(); - int absYear = Math.abs(year); - if (absYear < 1000) { + int year = date.getYear(), + absYear = Math.abs(year); + if (absYear < 10000) { if (year < 0) { buf.append('-'); } - buf.repeat('0', absYear < 10 ? 3 : absYear < 100 ? 2 : 1); - buf.append(absYear); + DecimalDigits.appendQuad(buf, absYear); } else { if (year > 9999) { buf.append('+'); } buf.append(year); } - buf.append(month < 10 ? "-0" : "-").append(month) - .append(day < 10 ? "-0" : "-").append(day); + buf.append('-'); + DecimalDigits.appendPair(buf, date.getMonthValue()); + buf.append('-'); + DecimalDigits.appendPair(buf, date.getDayOfMonth()); } /** @@ -74,14 +73,14 @@ public final class DateTimeHelper { * Requires extra capacity of 18 to avoid StringBuilder reallocation. */ public static void formatTo(StringBuilder buf, LocalTime time) { - int hour = time.getHour(), - minute = time.getMinute(), - second = time.getSecond(), + DecimalDigits.appendPair(buf, time.getHour()); + buf.append(':'); + DecimalDigits.appendPair(buf, time.getMinute()); + int second = time.getSecond(), nano = time.getNano(); - buf.append(hour < 10 ? "0" : "").append(hour) - .append(minute < 10 ? ":0" : ":").append(minute); if ((second | nano) > 0) { - buf.append(second < 10 ? ":0" : ":").append(second); + buf.append(':'); + DecimalDigits.appendPair(buf, second); if (nano > 0) { buf.append('.'); int zeros = 9 - DecimalDigits.stringSize(nano); diff --git a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java index 6c0c745651e..b55b6ce63b0 100644 --- a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java +++ b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java @@ -25,6 +25,8 @@ package jdk.internal.util; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.Stable; @@ -36,6 +38,7 @@ import static jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET; * @since 21 */ public final class DecimalDigits { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); private static final Unsafe UNSAFE = Unsafe.getUnsafe(); /** @@ -443,4 +446,56 @@ public final class DecimalDigits { assert charPos >= 0 && charPos < (buf.length >> 1); UNSAFE.putCharUnaligned(buf, ARRAY_BYTE_BASE_OFFSET + ((long) charPos << 1), (char) c); } + + /** + * Appends the two-digit string representation of the {@code int} + * argument to the given {@code StringBuilder}. + *

    + * The integer {@code v} is formatted as two decimal digits. + * Values from 0 to 9 are formatted with a leading zero (e.g., 5 becomes "05"), + * and values from 10 to 99 are formatted as regular two-digit numbers. + * If the value is outside the range 0-99, the behavior is unspecified. + * + * @param buf the {@code StringBuilder} to append to. + * @param v the {@code int} value (should be between 0 and 99 inclusive). + */ + public static void appendPair(StringBuilder buf, int v) { + // The & 0x7f operation keeps the index within the safe range [0, 127] for the DIGITS array, + // which allows the JIT compiler to eliminate array bounds checks for performance. + int packed = DIGITS[v & 0x7f]; + // The temporary String and byte[] objects created here are typically eliminated + // by the JVM's escape analysis and scalar replacement optimizations during + // runtime compilation, avoiding actual heap allocations in optimized code. + buf.append( + JLA.uncheckedNewStringWithLatin1Bytes( + new byte[] {(byte) packed, (byte) (packed >> 8)})); + } + + /** + * Appends the four-digit string representation of the {@code int} + * argument to the given {@code StringBuilder}. + *

    + * The integer {@code v} is formatted as four decimal digits. + * Values from 0 to 9 are formatted with leading zeros (e.g., 5 becomes "0005"), + * values from 10 to 99 add two leading zeros (e.g., 25 becomes "0025"), + * values from 100 to 999 add one leading zero (e.g., 123 becomes "0123"), + * and values from 1000 to 9999 have no leading zeros. + * If the value is outside the range 0-9999, the behavior is unspecified. + * + * @param buf the {@code StringBuilder} to append to. + * @param v the {@code int} value (should be between 0 and 9999 inclusive). + */ + public static void appendQuad(StringBuilder buf, int v) { + // The & 0x7f operation keeps the index within the safe range [0, 127] for the DIGITS array, + // which allows the JIT compiler to eliminate array bounds checks for performance. + int packedHigh = DIGITS[(v / 100) & 0x7f]; + int packedLow = DIGITS[(v % 100) & 0x7f]; + // The temporary String and byte[] objects created here are typically eliminated + // by the JVM's escape analysis and scalar replacement optimizations during + // runtime compilation, avoiding actual heap allocations in optimized code. + buf.append( + JLA.uncheckedNewStringWithLatin1Bytes( + new byte[] {(byte) packedHigh, (byte) (packedHigh >> 8), + (byte) packedLow, (byte) (packedLow >> 8)})); + } } diff --git a/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java b/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java index 46885e12adf..4221ec22de3 100644 --- a/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java +++ b/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java @@ -28,19 +28,17 @@ package jdk.internal.util; import jdk.internal.vm.annotation.ForceInline; -/** - * Helper to JDK UTF putChar and Calculate length - * - * @since 24 - */ -public abstract class ModifiedUtf { - // Maximum number of bytes allowed for a Modified UTF-8 encoded string - // in a ClassFile constant pool entry (CONSTANT_Utf8_info). +/// Utilities for string encoding and decoding with the +/// [Modified UTF-8][java.io.DataInput##modified-utf-8] format. +public final class ModifiedUtf { + /// Maximum number of bytes allowed for a Modified UTF-8 encoded string + /// in a [java.lang.classfile.constantpool.Utf8Entry] or a hotspot `Symbol`. public static final int CONSTANT_POOL_UTF8_MAX_BYTES = 65535; private ModifiedUtf() { } + /// Writes a char to the pre-sized modified UTF buffer. @ForceInline public static int putChar(byte[] buf, int offset, char c) { if (c != 0 && c < 0x80) { @@ -58,11 +56,23 @@ public abstract class ModifiedUtf { return offset; } - /** - * Calculate the utf length of a string - * @param str input string - * @param countNonZeroAscii the number of non-zero ascii characters in the prefix calculated by JLA.countNonZeroAscii(str) - */ + /// Calculate the encoded length of an input String. + /// For many workloads that have fast paths for ASCII-only prefixes, + /// [#utfLen(String, int)] skips scanning that prefix. + /// + /// @param str input string + public static long utfLen(String str) { + return utfLen(str, 0); + } + + /// Calculate the encoded length of trailing parts of an input String, + /// after [jdk.internal.access.JavaLangAccess#countNonZeroAscii(String)] + /// calculates the number of contiguous single-byte characters in the + /// beginning of the string. + /// + /// @param str input string + /// @param countNonZeroAscii the number of non-zero ascii characters in the + /// prefix calculated by JLA.countNonZeroAscii(str) @ForceInline public static long utfLen(String str, int countNonZeroAscii) { long utflen = str.length(); @@ -74,11 +84,11 @@ public abstract class ModifiedUtf { return utflen; } - /** - * Checks whether the Modified UTF-8 encoded length of the given string - * fits within the ClassFile constant pool limit (u2 length = 65535 bytes). - * @param str the string to check - */ + /// Checks whether an input String can be encoded in a + /// [java.lang.classfile.constantpool.Utf8Entry], or represented as a + /// hotspot `Symbol` (which has the same length limit). + /// + /// @param str input string @ForceInline public static boolean isValidLengthInConstantPool(String str) { // Quick approximation: each char can be at most 3 bytes in Modified UTF-8. @@ -91,7 +101,7 @@ public abstract class ModifiedUtf { return false; } // Check exact Modified UTF-8 length. - long utfLen = utfLen(str, 0); + long utfLen = utfLen(str); return utfLen <= CONSTANT_POOL_UTF8_MAX_BYTES; } } diff --git a/src/java.base/share/classes/jdk/internal/util/regex/CaseFolding.java.template b/src/java.base/share/classes/jdk/internal/util/regex/CaseFolding.java.template deleted file mode 100644 index 8ffbde6c535..00000000000 --- a/src/java.base/share/classes/jdk/internal/util/regex/CaseFolding.java.template +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.internal.util.regex; - -import java.util.Arrays; -import java.util.Map; -import java.util.Objects; - -import static java.util.Map.entry; - -public final class CaseFolding { - - private static final Map expanded_case_map = Map.ofEntries( -%%%Entries - ); - - private static final int[] expanded_case_cps = expanded_case_map.keySet() - .stream() - .mapToInt(Integer::intValue) - .toArray(); - - private CaseFolding() {} - - /** - * Returns an expansion set to "close" a given regex Unicode character class range for case-sensitive - * matching, according to the - * Simple Loose Matches - * rule defined in Unicode Technical Standard #18: Unicode Regular Expressions. - *

    - * To conform with Level 1 of UTS #18, specifically RL1.5: Simple Loose Matches, simple case folding must - * be applied to literals and (optionally) to character classes. When applied to character classes, each - * character class is expected to be closed under simple case folding. See the standard for the - * detailed explanation and example of "closed". - *

    - * RL1.5 states: To meet this requirement, an implementation that supports case-sensitive matching should - *

      - *
    1. Provide at least the simple, default Unicode case-insensitive matching, and
    2. - *
    3. Specify which character properties or constructs are closed under the matching.
    4. - *
    - *

    - * In the {@code Pattern} implementation, 5 types of constructs maybe case-sensitive when matching: - * back-refs, string slice (sequences), single, family(char-property) and class range. Single and - * family may appears independently or within a class. - *

    - * For loose/case-insensitive matching, the back-refs, slices and singles apply {code toUpperCase} and - * {@code toLowerCase} to both the pattern and the input string. This effectively 'close' the class for - * matching. - *

    - * The family/char-properties are not "closed" and should remain unchanged. This is acceptable per RL1.5, - * if their behavior is clearly specified. - *

    - * This method addresses that requirement for the "range" construct within in character class by computing - * the additional characters that should be included to close the range under simple case folding: - *

    - * For each character in the input range {@code [start, end]} (inclusive), if the character has a simple - * case folding mapping in Unicode's CaseFolding.txt, the mapping is not a round-trip map, and the mapped - * character is not already in the range, then that mapped character (typically lowercase) is added to - * the expansion set. - *

    - * This allows regex character class "range" implementation to use the returned expansion set to support - * additional case-insensitive matching, without duplicating characters already covered by the existing - * regex range implementation. The expectation is the matching is done using both the uppercase and - * lowercase forms of the input character, for example - * - *

    {@code
    -     *
    -     *     ch -> inRange(lower, Character.toUpperCase(ch), upper) ||
    -     *           inRange(lower, Character.toLower(ch), upper) ||
    -     *           additionalClosingCharacters.contains(Character.toUpperCase(ch)) ||
    -     *           additionalClosingCharacters.contains(Character.toUpperCase(ch))
    -     * }
    - * - *

    - * @spec https://www.unicode.org/reports/tr18/#Simple_Loose_Matches - * @param start the starting code point of the character range - * @param end the ending code point of the character range - * @return a {@code int[]} containing the all simple case equivalents of characters in the range, excluding - * those already in the range - */ - public static int[] getClassRangeClosingCharacters(int start, int end) { - int[] expanded = new int[expanded_case_cps.length]; - int off = 0; - for (int cp : expanded_case_cps) { - if (cp >= start && cp <= end) { - int folding = expanded_case_map.get(cp); - if (folding < start || folding > end) { - expanded[off++] = folding; - } - } - } - return Arrays.copyOf(expanded, off); - } -} diff --git a/src/java.base/share/classes/jdk/internal/util/regex/Grapheme.java b/src/java.base/share/classes/jdk/internal/util/regex/Grapheme.java index 34a69c3045f..303a76cb545 100644 --- a/src/java.base/share/classes/jdk/internal/util/regex/Grapheme.java +++ b/src/java.base/share/classes/jdk/internal/util/regex/Grapheme.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,9 +35,9 @@ public final class Grapheme { *

    * See Unicode Standard Annex #29 Unicode Text Segmentation for the specification * for the extended grapheme cluster boundary rules. The following implementation - * is based on the annex for Unicode version 16.0. + * is based on the annex for Unicode version 17.0. * - * @spec http://www.unicode.org/reports/tr29/tr29-45.html + * @spec http://www.unicode.org/reports/tr29/tr29-47.html * @param src the {@code CharSequence} to be scanned * @param off offset to start looking for the next boundary in the src * @param limit limit offset in the src (exclusive) @@ -283,7 +283,6 @@ public final class Grapheme { case 0x113D1: case 0x1193F: case 0x11941: - case 0x11A3A: case 0x11A84: case 0x11A85: case 0x11A86: diff --git a/src/java.base/share/classes/jdk/internal/util/regex/IndicConjunctBreak.java.template b/src/java.base/share/classes/jdk/internal/util/regex/IndicConjunctBreak.java.template index fc0e6605eca..149b1dce660 100644 --- a/src/java.base/share/classes/jdk/internal/util/regex/IndicConjunctBreak.java.template +++ b/src/java.base/share/classes/jdk/internal/util/regex/IndicConjunctBreak.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,8 +49,9 @@ final class IndicConjunctBreak { } static boolean isConsonant(int cp) { - // fast check - Devanagari to Malayalam - if (cp < 0x0900 || cp > 0x0D7F) { + // fast check - return false for code points below + // the Devanagari range (lowest among Indic scripts) + if (cp < 0x0900) { return false; } diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 3ae84fdf198..70a79390828 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -262,7 +262,6 @@ module java.base { jdk.jfr; exports jdk.internal.util to java.desktop, - java.net.http, java.prefs, java.security.jgss, java.smartcardio, diff --git a/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java b/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java index bd5ea6d7635..b3671d19333 100644 --- a/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java +++ b/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java @@ -63,33 +63,24 @@ public class BytecodeDescriptor { /// @throws TypeNotPresentException if a reference type cannot be found by /// the loader (before the descriptor is found invalid) public static List> parseMethod(String descriptor, ClassLoader loader) { - return parseMethod(descriptor, 0, descriptor.length(), loader); - } - - /** - * @param loader the class loader in which to look up the types (null means - * bootstrap class loader) - */ - static List> parseMethod(String bytecodeSignature, - int start, int end, ClassLoader loader) { - String str = bytecodeSignature; - int[] i = {start}; + int end = descriptor.length(); // implicit null check + int[] i = {0}; var ptypes = new ArrayList>(); - if (i[0] < end && str.charAt(i[0]) == '(') { + if (i[0] < end && descriptor.charAt(i[0]) == '(') { ++i[0]; // skip '(' - while (i[0] < end && str.charAt(i[0]) != ')') { - Class pt = parseSig(str, i, end, loader); + while (i[0] < end && descriptor.charAt(i[0]) != ')') { + Class pt = parseSig(descriptor, i, end, loader); if (pt == null || pt == void.class) - parseError(str, "bad argument type"); + parseError(descriptor, "bad argument type"); ptypes.add(pt); } ++i[0]; // skip ')' } else { - parseError(str, "not a method type"); + parseError(descriptor, "not a method type"); } - Class rtype = parseSig(str, i, end, loader); + Class rtype = parseSig(descriptor, i, end, loader); if (rtype == null || i[0] != end) - parseError(str, "bad return type"); + parseError(descriptor, "bad return type"); ptypes.add(rtype); return ptypes; } @@ -115,8 +106,22 @@ public class BytecodeDescriptor { if (i[0] == end) return null; char c = str.charAt(i[0]++); if (c == 'L') { - int begc = i[0], endc = str.indexOf(';', begc); - if (endc < 0) return null; + int begc = i[0]; + int identifierStart = begc; + int endc; + while (true) { + int next = nextNonIdentifier(str, identifierStart, end); + if (identifierStart == next || next >= end) return null; // Empty name segment, or the end + char ch = str.charAt(next); + if (ch == ';') { + endc = next; + break; + } else if (ch == '/') { + identifierStart = next + 1; // Next name segment + } else { + return null; // Bad char [ or . + } + } i[0] = endc+1; String name = str.substring(begc, endc).replace('/', '.'); try { @@ -148,6 +153,23 @@ public class BytecodeDescriptor { } } + private static final int CHECK_OFFSET = 32; + private static final long NON_IDENTIFIER_MASK = (1L << ('.' - CHECK_OFFSET)) + | (1L << ('/' - CHECK_OFFSET)) + | (1L << (';' - CHECK_OFFSET)) + | (1L << ('[' - CHECK_OFFSET)); + + private static int nextNonIdentifier(String str, int index, int end) { + while (index < end) { + int check = str.charAt(index) - CHECK_OFFSET; + if ((check & -Long.SIZE) == 0 && (NON_IDENTIFIER_MASK & (1L << check)) != 0) { + break; + } + index++; + } + return index; + } + public static String unparse(Class type) { if (type == Object.class) { return "Ljava/lang/Object;"; diff --git a/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/src/java.base/share/classes/sun/launcher/LauncherHelper.java index 81a4fe32110..9badf2beaeb 100644 --- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java +++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java @@ -103,6 +103,7 @@ public final class LauncherHelper { private static final String ADD_EXPORTS = "Add-Exports"; private static final String ADD_OPENS = "Add-Opens"; private static final String ENABLE_NATIVE_ACCESS = "Enable-Native-Access"; + private static final String ENABLE_FINAL_FIELD_MUTATION = "Enable-Final-Field-Mutation"; private static StringBuilder outBuf = new StringBuilder(); @@ -647,6 +648,8 @@ public final class LauncherHelper { if (opens != null) { addExportsOrOpens(opens, true); } + + // Enable-Native-Access String enableNativeAccess = mainAttrs.getValue(ENABLE_NATIVE_ACCESS); if (enableNativeAccess != null) { if (!enableNativeAccess.equals("ALL-UNNAMED")) { @@ -655,6 +658,16 @@ public final class LauncherHelper { Modules.addEnableNativeAccessToAllUnnamed(); } + // Enable-Final-Field-Mutation + String enableFinalFieldMutation = mainAttrs.getValue(ENABLE_FINAL_FIELD_MUTATION); + if (enableFinalFieldMutation != null) { + if (!enableFinalFieldMutation.equals("ALL-UNNAMED")) { + abort(null, "java.launcher.jar.error.illegal.effm.value", + enableFinalFieldMutation); + } + Modules.addEnableFinalMutationToAllUnnamed(); + } + /* * Hand off to FXHelper if it detects a JavaFX application * This must be done after ensuring a Main-Class entry diff --git a/src/java.base/share/classes/sun/launcher/resources/launcher.properties b/src/java.base/share/classes/sun/launcher/resources/launcher.properties index 83e08a3e11c..739ef8b8a29 100644 --- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties +++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties @@ -70,6 +70,14 @@ java.launcher.opt.footer = \ \ by code in modules for which native access is not explicitly enabled.\n\ \ is one of "deny", "warn" or "allow". The default value is "warn".\n\ \ This option will be removed in a future release.\n\ +\ --enable-final-field-mutation [,...]\n\ +\ allow code in the specified modules to mutate final instance fields.\n\ +\ can also be ALL-UNNAMED to indicate code on the class path.\n\ +\ --illegal-final-field-mutation=\n\ +\ allow or deny final field mutation by code in modules for which final\n\ +\ field mutation is not explicitly enabled.\n\ +\ is one of "deny", "warn", "debug", or "allow". The default value is "warn".\n\ +\ This option will be removed in a future release.\n\ \ --list-modules\n\ \ list observable modules and exit\n\ \ -d \n\ @@ -291,6 +299,8 @@ java.launcher.jar.error5=\ Error: An unexpected error occurred while trying to close file {0} java.launcher.jar.error.illegal.ena.value=\ Error: illegal value \"{0}\" for Enable-Native-Access manifest attribute. Only 'ALL-UNNAMED' is allowed +java.launcher.jar.error.illegal.effm.value=\ + Error: illegal value \"{0}\" for Enable-Final-Field-Mutation manifest attribute. Only 'ALL-UNNAMED' is allowed java.launcher.init.error=initialization error java.launcher.javafx.error1=\ Error: The JavaFX launchApplication method has the wrong signature, it\n\ diff --git a/src/java.base/share/classes/sun/nio/ch/Net.java b/src/java.base/share/classes/sun/nio/ch/Net.java index 9ec7975a35c..4564579d054 100644 --- a/src/java.base/share/classes/sun/nio/ch/Net.java +++ b/src/java.base/share/classes/sun/nio/ch/Net.java @@ -48,6 +48,8 @@ import java.nio.channels.UnresolvedAddressException; import java.nio.channels.UnsupportedAddressTypeException; import java.util.Enumeration; import java.util.Objects; +import java.lang.LazyConstant; +import java.util.function.Supplier; import sun.net.ext.ExtendedSocketOptions; import sun.net.util.IPAddressUtil; @@ -94,13 +96,14 @@ public class Net { return EXCLUSIVE_BIND; } - private static final StableValue SHUTDOWN_WRITE_BEFORE_CLOSE = StableValue.of(); + private static final LazyConstant SHUTDOWN_WRITE_BEFORE_CLOSE = LazyConstant.of(new Supplier() { + @Override public Boolean get() { return shouldShutdownWriteBeforeClose0(); }}); /** * Tells whether a TCP connection should be shutdown for writing before closing. */ static boolean shouldShutdownWriteBeforeClose() { - return SHUTDOWN_WRITE_BEFORE_CLOSE.orElseSet(Net::shouldShutdownWriteBeforeClose0); + return SHUTDOWN_WRITE_BEFORE_CLOSE.get(); } /** diff --git a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java index 5832e7f529a..57935ff5b00 100644 --- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java @@ -289,6 +289,7 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp */ private int implRead(byte[] b, int off, int len, long remainingNanos) throws IOException { int n = 0; + SocketException ex = null; FileDescriptor fd = beginRead(); try { if (connectionReset) @@ -307,18 +308,24 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp n = tryRead(fd, b, off, len); } } - return n; } catch (InterruptedIOException e) { throw e; } catch (ConnectionResetException e) { connectionReset = true; throw new SocketException("Connection reset"); } catch (IOException ioe) { - // throw SocketException to maintain compatibility - throw asSocketException(ioe); + // translate to SocketException to maintain compatibility + ex = asSocketException(ioe); } finally { endRead(n > 0); } + if (n <= 0 && isInputClosed) { + return -1; + } + if (ex != null) { + throw ex; + } + return n; } /** @@ -411,6 +418,7 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp */ private int implWrite(byte[] b, int off, int len) throws IOException { int n = 0; + SocketException ex = null; FileDescriptor fd = beginWrite(); try { configureNonBlockingIfNeeded(fd, false); @@ -419,15 +427,18 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp park(fd, Net.POLLOUT); n = tryWrite(fd, b, off, len); } - return n; } catch (InterruptedIOException e) { throw e; } catch (IOException ioe) { - // throw SocketException to maintain compatibility - throw asSocketException(ioe); + // translate to SocketException to maintain compatibility + ex = asSocketException(ioe); } finally { endWrite(n > 0); } + if (ex != null) { + throw ex; + } + return n; } /** diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java index aa69e29831d..b5db897b218 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, 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 @@ -128,7 +128,7 @@ public final class AnnotatedTypeFactory { private final Type type; private final LocationInfo location; private final TypeAnnotation[] allOnSameTargetTypeAnnotations; - private final Map, Annotation> annotations; + private final Map, Annotation> annotations; AnnotatedTypeBaseImpl(Type type, LocationInfo location, TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations) { @@ -162,11 +162,13 @@ public final class AnnotatedTypeFactory { @Override @SuppressWarnings("unchecked") public final T getDeclaredAnnotation(Class annotation) { + Objects.requireNonNull(annotation); return (T)annotations.get(annotation); } @Override public final T[] getDeclaredAnnotationsByType(Class annotation) { + Objects.requireNonNull(annotation); return AnnotationSupport.getDirectlyAndIndirectlyPresent(annotations, annotation); } diff --git a/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java b/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java index 75750d38f2f..560e9a4f7c9 100644 --- a/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java +++ b/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,8 @@ import java.lang.reflect.TypeVariable; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; + +import jdk.internal.reflect.ReflectionFactory; import sun.reflect.annotation.AnnotationSupport; import sun.reflect.annotation.TypeAnnotationParser; import sun.reflect.annotation.AnnotationType; @@ -125,18 +127,24 @@ public class TypeVariableImpl } /** - * Returns the {@code GenericDeclaration} object representing the + * Returns a {@code GenericDeclaration} object representing the * generic declaration that declared this type variable. * - * @return the generic declaration that declared this type variable. + * @return a generic declaration that declared this type variable. * * @since 1.5 */ + @SuppressWarnings("unchecked") public D getGenericDeclaration() { assert genericDeclaration instanceof Class || genericDeclaration instanceof Method || genericDeclaration instanceof Constructor : "Unexpected kind of GenericDeclaration"; - return genericDeclaration; + // If the `genericDeclaration` instance is mutable, we need to make a copy. + return switch (genericDeclaration) { + case Method method -> (D) ReflectionFactory.getReflectionFactory().copyMethod(method); + case Constructor ctor -> (D) ReflectionFactory.getReflectionFactory().copyConstructor(ctor); + default -> genericDeclaration; + }; } diff --git a/src/java.base/share/classes/sun/security/ec/ECKeyFactory.java b/src/java.base/share/classes/sun/security/ec/ECKeyFactory.java index 2530425fbd4..a753a105e6e 100644 --- a/src/java.base/share/classes/sun/security/ec/ECKeyFactory.java +++ b/src/java.base/share/classes/sun/security/ec/ECKeyFactory.java @@ -26,6 +26,7 @@ package sun.security.ec; import sun.security.pkcs.PKCS8Key; +import sun.security.util.KeyUtil; import java.security.*; import java.security.interfaces.*; @@ -213,11 +214,17 @@ public final class ECKeyFactory extends KeyFactorySpi { case ECPublicKeySpec e -> new ECPublicKeyImpl(e.getW(), e.getParams()); case PKCS8EncodedKeySpec p8 -> { - PKCS8Key p8key = new ECPrivateKeyImpl(p8.getEncoded()); - if (!p8key.hasPublicKey()) { - throw new InvalidKeySpecException("No public key found."); + byte[] encoded = p8.getEncoded(); + PKCS8Key p8key = null; + try { + p8key = new ECPrivateKeyImpl(encoded); + if (!p8key.hasPublicKey()) { + throw new InvalidKeySpecException("No public key found."); + } + yield new ECPublicKeyImpl(p8key.getPubKeyEncoded()); + } finally { + KeyUtil.clear(encoded, p8key); } - yield new ECPublicKeyImpl(p8key.getPubKeyEncoded()); } case null -> throw new InvalidKeySpecException( "keySpec must not be null"); diff --git a/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java b/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java index 65c4f093f27..1b69a5b22b4 100644 --- a/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java +++ b/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java @@ -75,6 +75,7 @@ public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey { @SuppressWarnings("serial") // Type of field is not Serializable private ECParameterSpec params; private byte[] domainParams; //Currently unsupported + private final byte SEC1v2 = 1; /** * Construct a key from its encoding. Called by the ECKeyFactory. @@ -92,34 +93,6 @@ public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey { throws InvalidKeyException { this.s = s; this.params = params; - makeEncoding(s); - - } - - ECPrivateKeyImpl(byte[] s, ECParameterSpec params) - throws InvalidKeyException { - this.arrayS = s.clone(); - this.params = params; - makeEncoding(s); - } - - private void makeEncoding(byte[] s) throws InvalidKeyException { - algid = new AlgorithmId - (AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params)); - DerOutputStream out = new DerOutputStream(); - out.putInteger(1); // version 1 - byte[] privBytes = s.clone(); - ArrayUtil.reverse(privBytes); - out.putOctetString(privBytes); - Arrays.fill(privBytes, (byte) 0); - DerValue val = DerValue.wrap(DerValue.tag_Sequence, out); - privKeyMaterial = val.toByteArray(); - val.clear(); - } - - private void makeEncoding(BigInteger s) throws InvalidKeyException { - algid = new AlgorithmId(AlgorithmId.EC_oid, - ECParameters.getAlgorithmParameters(params)); byte[] sArr = s.toByteArray(); // convert to fixed-length array int numOctets = (params.getOrder().bitLength() + 7) / 8; @@ -129,11 +102,33 @@ public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey { int length = Math.min(sArr.length, sOctets.length); System.arraycopy(sArr, inPos, sOctets, outPos, length); Arrays.fill(sArr, (byte) 0); + try { + makeEncoding(sOctets); + } finally { + Arrays.fill(sOctets, (byte) 0); + } + } + ECPrivateKeyImpl(byte[] s, ECParameterSpec params) + throws InvalidKeyException { + this.arrayS = s.clone(); + this.params = params; + byte[] privBytes = arrayS.clone(); + ArrayUtil.reverse(privBytes); + try { + makeEncoding(privBytes); + } finally { + Arrays.fill(privBytes, (byte) 0); + } + + } + + private void makeEncoding(byte[] privBytes) throws InvalidKeyException { + algid = new AlgorithmId(AlgorithmId.EC_oid, + ECParameters.getAlgorithmParameters(params)); DerOutputStream out = new DerOutputStream(); out.putInteger(1); // version 1 - out.putOctetString(sOctets); - Arrays.fill(sOctets, (byte) 0); + out.putOctetString(privBytes); DerValue val = DerValue.wrap(DerValue.tag_Sequence, out); privKeyMaterial = val.toByteArray(); val.clear(); @@ -181,7 +176,7 @@ public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey { } DerInputStream data = derValue.data; int version = data.getInteger(); - if (version != V2) { + if (version != SEC1v2) { throw new IOException("Version must be 1"); } byte[] privData = data.getOctetString(); @@ -253,4 +248,40 @@ public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey { throw new InvalidObjectException( "ECPrivateKeyImpl keys are not directly deserializable"); } + + // Parse the SEC1v2 encoding to extract public key, if available. + public static BitArray parsePublicBits(byte[] privateBytes) { + DerValue seq = null; + try { + seq = new DerValue(privateBytes); + if (seq.tag == DerValue.tag_Sequence) { + int version = seq.data.getInteger(); + if (version == 1) { // EC + seq.data.getDerValue(); // read pass the private key + if (seq.data.available() != 0) { + DerValue derValue = seq.data.getDerValue(); + // check for optional [0] EC domain parameters + if (derValue.isContextSpecific((byte) 0)) { + if (seq.data.available() == 0) { + return null; + } + derValue = seq.data.getDerValue(); + } + // [1] public key + if (derValue.isContextSpecific((byte) 1)) { + derValue = derValue.data.getDerValue(); + return derValue.getUnalignedBitString(); + } + } + } + } + } catch (IOException e) { + throw new IllegalArgumentException(e); + } finally { + if (seq != null) { + seq.clear(); + } + } + return null; + } } diff --git a/src/java.base/share/classes/sun/security/ec/XDHKeyFactory.java b/src/java.base/share/classes/sun/security/ec/XDHKeyFactory.java index c8fb6c0c11b..8f060705323 100644 --- a/src/java.base/share/classes/sun/security/ec/XDHKeyFactory.java +++ b/src/java.base/share/classes/sun/security/ec/XDHKeyFactory.java @@ -26,6 +26,7 @@ package sun.security.ec; import sun.security.pkcs.PKCS8Key; +import sun.security.util.KeyUtil; import java.security.*; import java.security.interfaces.XECKey; @@ -159,15 +160,20 @@ public class XDHKeyFactory extends KeyFactorySpi { yield new XDHPublicKeyImpl(params, publicKeySpec.getU()); } case PKCS8EncodedKeySpec p8 -> { - PKCS8Key p8key = new XDHPrivateKeyImpl(p8.getEncoded()); - if (!p8key.hasPublicKey()) { - throw new InvalidKeySpecException("No public key found."); + byte[] encoded = p8.getEncoded(); + PKCS8Key p8key = new XDHPrivateKeyImpl(encoded); + try { + if (!p8key.hasPublicKey()) { + throw new InvalidKeySpecException("No public key found."); + } + XDHPublicKeyImpl result = + new XDHPublicKeyImpl(p8key.getPubKeyEncoded()); + checkLockedParams(InvalidKeySpecException::new, + result.getParams()); + yield result; + } finally { + KeyUtil.clear(encoded, p8key); } - XDHPublicKeyImpl result = - new XDHPublicKeyImpl(p8key.getPubKeyEncoded()); - checkLockedParams(InvalidKeySpecException::new, - result.getParams()); - yield result; } case null -> throw new InvalidKeySpecException( "keySpec must not be null"); diff --git a/src/java.base/share/classes/sun/security/ec/ed/EdDSAKeyFactory.java b/src/java.base/share/classes/sun/security/ec/ed/EdDSAKeyFactory.java index 71ec14ba06f..d59e44d81db 100644 --- a/src/java.base/share/classes/sun/security/ec/ed/EdDSAKeyFactory.java +++ b/src/java.base/share/classes/sun/security/ec/ed/EdDSAKeyFactory.java @@ -26,6 +26,7 @@ package sun.security.ec.ed; import sun.security.pkcs.PKCS8Key; +import sun.security.util.KeyUtil; import java.security.*; import java.security.interfaces.*; @@ -152,11 +153,17 @@ public class EdDSAKeyFactory extends KeyFactorySpi { yield new EdDSAPublicKeyImpl(params, publicKeySpec.getPoint()); } case PKCS8EncodedKeySpec p8 -> { - PKCS8Key p8key = new EdDSAPrivateKeyImpl(p8.getEncoded()); - if (!p8key.hasPublicKey()) { - throw new InvalidKeySpecException("No public key found."); + byte[] encoded = p8.getEncoded(); + PKCS8Key p8key = null; + try { + p8key = new EdDSAPrivateKeyImpl(encoded); + if (!p8key.hasPublicKey()) { + throw new InvalidKeySpecException("No public key found."); + } + yield new EdDSAPublicKeyImpl(p8key.getPubKeyEncoded()); + } finally { + KeyUtil.clear(encoded, p8key); } - yield new EdDSAPublicKeyImpl(p8key.getPubKeyEncoded()); } case null -> throw new InvalidKeySpecException( "keySpec must not be null"); diff --git a/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java b/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java index b7cc5e7057f..dea87bd0a32 100644 --- a/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java +++ b/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java @@ -26,6 +26,7 @@ package sun.security.pkcs; import jdk.internal.access.SharedSecrets; +import sun.security.ec.ECPrivateKeyImpl; import sun.security.util.*; import sun.security.x509.AlgorithmId; import sun.security.x509.X509Key; @@ -104,11 +105,29 @@ public class PKCS8Key implements PrivateKey, InternalPrivateKey { } } - private PKCS8Key(byte[] privEncoding, byte[] pubEncoding) + /** + * Constructor that takes both public and private encodings. + * + * If the private key includes a public key encoding (like an EC key in + * SEC1v2 format), and a specified public key matches it, the existing + * encoding is reused rather than recreated. + */ + public PKCS8Key(byte[] publicEncoding, byte[] privateEncoding) throws InvalidKeyException { - this(privEncoding); - pubKeyEncoded = pubEncoding; - version = V2; + this(privateEncoding); + if (publicEncoding != null) { + if (pubKeyEncoded != null) { + if (!Arrays.equals(pubKeyEncoded, publicEncoding)) { + Arrays.fill(privKeyMaterial, (byte) 0x0); + throw new InvalidKeyException("PrivateKey " + + "encoding has a public key that does not match " + + "the given PublicKey"); + } + } else { + pubKeyEncoded = publicEncoding; + version = V2; + } + } } public int getVersion() { @@ -137,6 +156,14 @@ public class PKCS8Key implements PrivateKey, InternalPrivateKey { // Store key material for subclasses to parse privKeyMaterial = val.data.getOctetString(); + // Special check and parsing for ECDSA's SEC1v2 format + if (algid.getOID().equals(AlgorithmId.EC_oid)) { + var bits = ECPrivateKeyImpl.parsePublicBits(privKeyMaterial); + if (bits != null) { + pubKeyEncoded = new X509Key(algid, bits).getEncoded(); + } + } + // PKCS8 v1 typically ends here if (val.data.available() == 0) { return; @@ -271,19 +298,24 @@ public class PKCS8Key implements PrivateKey, InternalPrivateKey { * With a given encoded Public and Private key, generate and return a * PKCS8v2 DER-encoded byte[]. * - * @param pubKeyEncoded DER-encoded PublicKey + * @param pubKeyEncoded DER-encoded PublicKey, this may be null. * @param privKeyEncoded DER-encoded PrivateKey * @return DER-encoded byte array * @throws IOException thrown on encoding failure */ public static byte[] getEncoded(byte[] pubKeyEncoded, byte[] privKeyEncoded) throws IOException { + PKCS8Key pkcs8Key; try { - return new PKCS8Key(privKeyEncoded, pubKeyEncoded). - generateEncoding(); + pkcs8Key = new PKCS8Key(pubKeyEncoded, privKeyEncoded); } catch (InvalidKeyException e) { throw new IOException(e); } + try { + return pkcs8Key.generateEncoding().clone(); + } finally { + pkcs8Key.clear(); + } } /** @@ -295,7 +327,7 @@ public class PKCS8Key implements PrivateKey, InternalPrivateKey { private synchronized byte[] getEncodedInternal() { if (encodedKey == null) { try { - encodedKey = generateEncoding(); + generateEncoding(); } catch (IOException e) { return null; } @@ -326,7 +358,6 @@ public class PKCS8Key implements PrivateKey, InternalPrivateKey { throw new IOException(e); } - // X509Key x = X509Key.parse(pubKeyEncoded); DerOutputStream pubOut = new DerOutputStream(); pubOut.putUnalignedBitString(x.getKey()); out.writeImplicit( diff --git a/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java b/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java index 3e771c015f4..73ca0c6bf16 100644 --- a/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java +++ b/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -627,6 +627,10 @@ public abstract sealed class JavaKeyStore extends KeyStoreSpi { dos.write(digest); dos.flush(); + + if (debug != null) { + emitWeakKeyStoreWarning(); + } } } @@ -790,6 +794,10 @@ public abstract sealed class JavaKeyStore extends KeyStoreSpi { privateKeyCount + ". trusted key count: " + trustedKeyCount); } + if (debug != null) { + emitWeakKeyStoreWarning(); + } + /* * If a password has been provided, we check the keyed digest * at the end. If this check fails, the store has been tampered @@ -838,4 +846,16 @@ public abstract sealed class JavaKeyStore extends KeyStoreSpi { } return passwdBytes; } + + private void emitWeakKeyStoreWarning() { + String type = this.getClass().getSimpleName(). + toUpperCase(Locale.ROOT); + if (type.equals("JKS")){ + debug.println("WARNING: JKS uses outdated cryptographic " + + "algorithms and will be removed in a future " + + "release. Migrate to PKCS12 using:"); + debug.println("keytool -importkeystore -srckeystore " + + "-destkeystore -deststoretype pkcs12"); + } + } } diff --git a/src/java.base/share/classes/sun/security/provider/X509Factory.java b/src/java.base/share/classes/sun/security/provider/X509Factory.java index 1a8ace55fc8..f732c7c0455 100644 --- a/src/java.base/share/classes/sun/security/provider/X509Factory.java +++ b/src/java.base/share/classes/sun/security/provider/X509Factory.java @@ -27,7 +27,7 @@ package sun.security.provider; import java.io.*; -import java.security.PEMRecord; +import java.security.PEM; import java.security.cert.*; import java.util.*; @@ -559,7 +559,7 @@ public class X509Factory extends CertificateFactorySpi { return bout.toByteArray(); } else { try { - PEMRecord rec; + PEM rec; try { rec = Pem.readPEM(is, (c == '-' ? true : false)); } catch (EOFException e) { 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 ed5e079bf44..d172206326f 100644 --- a/src/java.base/share/classes/sun/security/ssl/Alert.java +++ b/src/java.base/share/classes/sun/security/ssl/Alert.java @@ -238,7 +238,7 @@ public enum Alert { TransportContext tc = (TransportContext)context; AlertMessage am = new AlertMessage(tc, m); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("Received alert message", am); } diff --git a/src/java.base/share/classes/sun/security/ssl/AlpnExtension.java b/src/java.base/share/classes/sun/security/ssl/AlpnExtension.java index aa5933ddab0..f03a65c8410 100644 --- a/src/java.base/share/classes/sun/security/ssl/AlpnExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/AlpnExtension.java @@ -157,7 +157,7 @@ final class AlpnExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(SSLExtension.CH_ALPN)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.info( "Ignore client unavailable extension: " + SSLExtension.CH_ALPN.name); @@ -170,7 +170,7 @@ final class AlpnExtension { String[] laps = chc.sslConfig.applicationProtocols; if ((laps == null) || (laps.length == 0)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.info( "No available application protocols"); } @@ -183,7 +183,7 @@ final class AlpnExtension { int length = ap.getBytes(alpnCharset).length; if (length == 0) { // log the configuration problem - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.severe( "Application protocol name cannot be empty"); } @@ -197,7 +197,7 @@ final class AlpnExtension { listLength += (length + 1); } else { // log the configuration problem - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.severe( "Application protocol name (" + ap + ") exceeds the size limit (" + @@ -212,7 +212,7 @@ final class AlpnExtension { if (listLength > MAX_AP_LIST_LENGTH) { // log the configuration problem - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.severe( "The configured application protocols (" + Arrays.toString(laps) + @@ -266,7 +266,7 @@ final class AlpnExtension { if (!shc.sslConfig.isAvailable(SSLExtension.CH_ALPN)) { shc.applicationProtocol = ""; shc.conContext.applicationProtocol = ""; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.info( "Ignore server unavailable extension: " + SSLExtension.CH_ALPN.name); @@ -288,7 +288,7 @@ final class AlpnExtension { if (noAPSelector && noAlpnProtocols) { shc.applicationProtocol = ""; shc.conContext.applicationProtocol = ""; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore server unenabled extension: " + SSLExtension.CH_ALPN.name); @@ -378,7 +378,7 @@ final class AlpnExtension { (AlpnSpec)shc.handshakeExtensions.get(SSLExtension.CH_ALPN); if (requestedAlps == null) { // Ignore, this extension was not requested and accepted. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extension: " + SSLExtension.SH_ALPN.name); @@ -423,7 +423,7 @@ final class AlpnExtension { // Ignore, no negotiated application layer protocol. shc.applicationProtocol = ""; shc.conContext.applicationProtocol = ""; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Ignore, no negotiated application layer protocol"); } diff --git a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java index 2125a148162..2d03d5fef98 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java @@ -94,7 +94,7 @@ final class CertSignAlgsExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable( SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable " + "signature_algorithms_cert extension"); @@ -144,7 +144,7 @@ final class CertSignAlgsExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable( SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable " + "signature_algorithms_cert extension"); @@ -235,7 +235,7 @@ final class CertSignAlgsExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable( SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable " + "signature_algorithms_cert extension"); @@ -283,7 +283,7 @@ final class CertSignAlgsExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable( SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable " + "signature_algorithms_cert extension"); diff --git a/src/java.base/share/classes/sun/security/ssl/CertStatusExtension.java b/src/java.base/share/classes/sun/security/ssl/CertStatusExtension.java index 49713b6db11..d6c1cec5735 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertStatusExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/CertStatusExtension.java @@ -144,7 +144,7 @@ final class CertStatusExtension { if (statusType == CertStatusRequestType.OCSP.id) { this.statusRequest = new OCSPStatusRequest(statusType, encoded); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.info( "Unknown certificate status request " + "(status type: " + statusType + ")"); @@ -196,7 +196,7 @@ final class CertStatusExtension { if (type == CertStatusRequestType.OCSP.id) { this.statusResponse = new OCSPStatusResponse(type, respData); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.info( "Unknown certificate status response " + "(status type: " + type + ")"); @@ -557,7 +557,7 @@ final class CertStatusExtension { } if (!chc.sslConfig.isAvailable(SSLExtension.CH_STATUS_REQUEST)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extension: " + SSLExtension.CH_STATUS_REQUEST.name); @@ -598,7 +598,7 @@ final class CertStatusExtension { ServerHandshakeContext shc = (ServerHandshakeContext)context; if (!shc.sslConfig.isAvailable(SSLExtension.CH_STATUS_REQUEST)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Ignore unavailable extension: " + SSLExtension.CH_STATUS_REQUEST.name); } @@ -656,7 +656,7 @@ final class CertStatusExtension { shc.handshakeExtensions.get(SSLExtension.CH_STATUS_REQUEST); if (spec == null) { // Ignore, no status_request extension requested. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest("Ignore unavailable extension: " + SSLExtension.CH_STATUS_REQUEST.name); } @@ -666,7 +666,7 @@ final class CertStatusExtension { // Is it a session resuming? if (shc.isResumption) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "No status_request response for session resuming"); } @@ -839,7 +839,7 @@ final class CertStatusExtension { statusRequests.add( new OCSPStatusRequest(statusType, encoded)); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.info( "Unknown certificate status request " + "(status type: " + statusType + ")"); @@ -915,7 +915,7 @@ final class CertStatusExtension { } if (!chc.sslConfig.isAvailable(SSLExtension.CH_STATUS_REQUEST_V2)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "Ignore unavailable status_request_v2 extension"); } @@ -957,7 +957,7 @@ final class CertStatusExtension { ServerHandshakeContext shc = (ServerHandshakeContext)context; if (!shc.sslConfig.isAvailable(SSLExtension.CH_STATUS_REQUEST_V2)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "Ignore unavailable status_request_v2 extension"); } @@ -1017,7 +1017,7 @@ final class CertStatusExtension { shc.handshakeExtensions.get(SSLExtension.CH_STATUS_REQUEST_V2); if (spec == null) { // Ignore, no status_request_v2 extension requested. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "Ignore unavailable status_request_v2 extension"); } @@ -1027,7 +1027,7 @@ final class CertStatusExtension { // Is it a session resuming? if (shc.isResumption) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "No status_request_v2 response for session resumption"); } @@ -1112,7 +1112,7 @@ final class CertStatusExtension { // Stapling needs to be active and have valid data to proceed if (shc.stapleParams == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "Stapling is disabled for this connection"); } @@ -1121,7 +1121,7 @@ final class CertStatusExtension { // There needs to be a non-null CertificateEntry to proceed if (shc.currentCertEntry == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest("Found null CertificateEntry in context"); } return null; @@ -1139,7 +1139,7 @@ final class CertStatusExtension { byte[] respBytes = shc.stapleParams.responseMap.get(x509Cert); if (respBytes == null) { // We're done with this entry. Clear it from the context - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest("No status response found for " + x509Cert.getSubjectX500Principal()); @@ -1149,7 +1149,7 @@ final class CertStatusExtension { } // Build a proper response buffer from the stapling information - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest("Found status response for " + x509Cert.getSubjectX500Principal() + ", response length: " + respBytes.length); @@ -1208,7 +1208,7 @@ final class CertStatusExtension { respList.add(spec.statusResponse.encodedResponse); chc.handshakeSession.setStatusResponses(respList); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Ignoring stapled data on resumed session"); } diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java b/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java index 43bac16f0ea..cc513eb30ba 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java @@ -192,7 +192,7 @@ final class CertificateAuthoritiesExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable( SSLExtension.CH_CERTIFICATE_AUTHORITIES)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable " + "certificate_authorities extension"); @@ -205,7 +205,7 @@ final class CertificateAuthoritiesExtension { X509Certificate[] caCerts = chc.sslContext.getX509TrustManager().getAcceptedIssuers(); if (caCerts.length == 0) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "No available certificate authorities"); } @@ -216,7 +216,7 @@ final class CertificateAuthoritiesExtension { List encodedCAs = CertificateAuthoritiesSpec.getEncodedAuthorities(caCerts); if (encodedCAs.isEmpty()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "The number of CAs exceeds the maximum size " + "of the certificate_authorities extension"); @@ -270,7 +270,7 @@ final class CertificateAuthoritiesExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable( SSLExtension.CH_CERTIFICATE_AUTHORITIES)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable " + "certificate_authorities extension"); @@ -319,7 +319,7 @@ final class CertificateAuthoritiesExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable( SSLExtension.CR_CERTIFICATE_AUTHORITIES)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable " + "certificate_authorities extension"); @@ -332,7 +332,7 @@ final class CertificateAuthoritiesExtension { X509Certificate[] caCerts = shc.sslContext.getX509TrustManager().getAcceptedIssuers(); if (caCerts.length == 0) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "No available certificate authorities"); } @@ -343,7 +343,7 @@ final class CertificateAuthoritiesExtension { List encodedCAs = CertificateAuthoritiesSpec.getEncodedAuthorities(caCerts); if (encodedCAs.isEmpty()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Too many certificate authorities to use " + "the certificate_authorities extension"); @@ -397,7 +397,7 @@ final class CertificateAuthoritiesExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable( SSLExtension.CR_CERTIFICATE_AUTHORITIES)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable " + "certificate_authorities extension"); 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 d4587d35ae9..2a2db34cab9 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java @@ -265,7 +265,7 @@ final class CertificateMessage { shc.handshakeSession.setLocalCertificates(x509Possession.popCerts); T12CertificateMessage cm = new T12CertificateMessage(shc, x509Possession.popCerts); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced server Certificate handshake message", cm); } @@ -293,7 +293,7 @@ final class CertificateMessage { // an empty cert chain instead. if (x509Possession == null) { if (chc.negotiatedProtocol.useTLS10PlusSpec()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "No X.509 certificate for client authentication, " + "use empty Certificate message instead"); @@ -302,7 +302,7 @@ final class CertificateMessage { x509Possession = new X509Possession(null, new X509Certificate[0]); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "No X.509 certificate for client authentication, " + "send a no_certificate alert"); @@ -324,7 +324,7 @@ final class CertificateMessage { } T12CertificateMessage cm = new T12CertificateMessage(chc, x509Possession.popCerts); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced client Certificate handshake message", cm); } @@ -360,13 +360,13 @@ final class CertificateMessage { T12CertificateMessage cm = new T12CertificateMessage(hc, message); if (hc.sslConfig.isClientMode) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming server Certificate handshake message", cm); } onCertificate((ClientHandshakeContext)context, cm); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming client Certificate handshake message", cm); } @@ -501,7 +501,7 @@ final class CertificateMessage { try { thisSubjectAltNames = thisCert.getSubjectAlternativeNames(); } catch (CertificateParsingException cpe) { - if (SSLLogger.isOn && SSLLogger.isOn("handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("handshake")) { SSLLogger.fine( "Attempt to obtain subjectAltNames extension failed!"); } @@ -511,7 +511,7 @@ final class CertificateMessage { try { prevSubjectAltNames = prevCert.getSubjectAlternativeNames(); } catch (CertificateParsingException cpe) { - if (SSLLogger.isOn && SSLLogger.isOn("handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("handshake")) { SSLLogger.fine( "Attempt to obtain subjectAltNames extension failed!"); } @@ -980,7 +980,7 @@ final class CertificateMessage { certEnt.extensions.produce(shc, enabledCTExts); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced server Certificate message", cm); } @@ -997,7 +997,7 @@ final class CertificateMessage { ClientHelloMessage clientHello) { if (hc.peerRequestedCertSignSchemes == null || hc.peerRequestedCertSignSchemes.isEmpty()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "No signature_algorithms(_cert) in ClientHello"); } @@ -1021,7 +1021,7 @@ final class CertificateMessage { SSLPossession pos = X509Authentication .createPossession(hc, supportedKeyTypes); if (pos == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("No available authentication scheme"); } } @@ -1034,14 +1034,14 @@ final class CertificateMessage { SSLPossession pos = choosePossession(chc, clientHello); X509Certificate[] localCerts; if (pos == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("No available client authentication scheme"); } localCerts = new X509Certificate[0]; } else { chc.handshakePossessions.add(pos); if (!(pos instanceof X509Possession x509Possession)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "No X.509 certificate for client authentication"); } @@ -1067,7 +1067,7 @@ final class CertificateMessage { throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "Failed to produce client Certificate message", ce); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced client Certificate message", cm); } @@ -1108,13 +1108,13 @@ final class CertificateMessage { T13CertificateMessage cm = new T13CertificateMessage(hc, message); if (hc.sslConfig.isClientMode) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming server Certificate handshake message", cm); } onConsumeCertificate((ClientHandshakeContext)context, cm); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming client Certificate handshake message", cm); } 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 66b8c048703..a297d9d21b2 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -297,7 +297,7 @@ final class CertificateRequest { shc.sslContext.getX509TrustManager().getAcceptedIssuers(); T10CertificateRequestMessage crm = new T10CertificateRequestMessage( shc, caCerts, shc.negotiatedCipherSuite.keyExchange); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced CertificateRequest handshake message", crm); } @@ -360,7 +360,7 @@ final class CertificateRequest { T10CertificateRequestMessage crm = new T10CertificateRequestMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming CertificateRequest handshake message", crm); } @@ -400,7 +400,7 @@ final class CertificateRequest { } if (clientAlias == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("No available client authentication"); } return; @@ -408,7 +408,7 @@ final class CertificateRequest { PrivateKey clientPrivateKey = km.getPrivateKey(clientAlias); if (clientPrivateKey == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("No available client private key"); } return; @@ -416,7 +416,7 @@ final class CertificateRequest { X509Certificate[] clientCerts = km.getCertificateChain(clientAlias); if ((clientCerts == null) || (clientCerts.length == 0)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("No available client certificate"); } return; @@ -655,7 +655,7 @@ final class CertificateRequest { T12CertificateRequestMessage crm = new T12CertificateRequestMessage( shc, caCerts, shc.negotiatedCipherSuite.keyExchange, certReqSignAlgs); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced CertificateRequest handshake message", crm); } @@ -717,7 +717,7 @@ final class CertificateRequest { T12CertificateRequestMessage crm = new T12CertificateRequestMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming CertificateRequest handshake message", crm); } @@ -784,7 +784,7 @@ final class CertificateRequest { T12CertificateRequestMessage crm) { if (hc.peerRequestedCertSignSchemes == null || hc.peerRequestedCertSignSchemes.isEmpty()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("No signature and hash algorithms " + "in CertificateRequest"); } @@ -823,7 +823,7 @@ final class CertificateRequest { SSLPossession pos = X509Authentication .createPossession(hc, supportedKeyTypes); if (pos == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("No available authentication scheme"); } } @@ -933,7 +933,7 @@ final class CertificateRequest { SSLExtension[] extTypes = shc.sslConfig.getEnabledExtensions( SSLHandshake.CERTIFICATE_REQUEST, shc.negotiatedProtocol); crm.extensions.produce(shc, extTypes); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced CertificateRequest message", crm); } @@ -985,7 +985,7 @@ final class CertificateRequest { T13CertificateRequestMessage crm = new T13CertificateRequestMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming CertificateRequest handshake message", crm); } diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateStatus.java b/src/java.base/share/classes/sun/security/ssl/CertificateStatus.java index 11b2c5e587d..a1048e423d1 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateStatus.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateStatus.java @@ -281,7 +281,7 @@ final class CertificateStatus { new CertificateStatusMessage(chc, message); // Log the message - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming server CertificateStatus handshake message", cst); @@ -325,7 +325,7 @@ final class CertificateStatus { // Create the CertificateStatus message from info in the CertificateStatusMessage csm = new CertificateStatusMessage(shc); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced server CertificateStatus handshake message", csm); } @@ -358,7 +358,7 @@ final class CertificateStatus { // status_request[_v2] extension. 2) The CertificateStatus // message was not sent. This means that cert path checking // was deferred, but must happen immediately. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Server did not send CertificateStatus, " + "checking cert chain without status info."); } diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java b/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java index 09d07d8e62d..18ea2b9c3de 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java @@ -248,7 +248,7 @@ final class CertificateVerify { if (x509Possession == null || x509Possession.popPrivateKey == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "No X.509 credentials negotiated for CertificateVerify"); } @@ -258,7 +258,7 @@ final class CertificateVerify { S30CertificateVerifyMessage cvm = new S30CertificateVerifyMessage(chc, x509Possession); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced CertificateVerify handshake message", cvm); } @@ -300,7 +300,7 @@ final class CertificateVerify { S30CertificateVerifyMessage cvm = new S30CertificateVerifyMessage(shc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming CertificateVerify handshake message", cvm); } @@ -503,7 +503,7 @@ final class CertificateVerify { if (x509Possession == null || x509Possession.popPrivateKey == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "No X.509 credentials negotiated for CertificateVerify"); } @@ -513,7 +513,7 @@ final class CertificateVerify { T10CertificateVerifyMessage cvm = new T10CertificateVerifyMessage(chc, x509Possession); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced CertificateVerify handshake message", cvm); } @@ -555,7 +555,7 @@ final class CertificateVerify { T10CertificateVerifyMessage cvm = new T10CertificateVerifyMessage(shc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming CertificateVerify handshake message", cvm); } @@ -754,7 +754,7 @@ final class CertificateVerify { if (x509Possession == null || x509Possession.popPrivateKey == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "No X.509 credentials negotiated for CertificateVerify"); } @@ -764,7 +764,7 @@ final class CertificateVerify { T12CertificateVerifyMessage cvm = new T12CertificateVerifyMessage(chc, x509Possession); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced CertificateVerify handshake message", cvm); } @@ -806,7 +806,7 @@ final class CertificateVerify { T12CertificateVerifyMessage cvm = new T12CertificateVerifyMessage(shc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming CertificateVerify handshake message", cvm); } @@ -1092,7 +1092,7 @@ final class CertificateVerify { if (x509Possession == null || x509Possession.popPrivateKey == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "No X.509 credentials negotiated for CertificateVerify"); } @@ -1113,7 +1113,7 @@ final class CertificateVerify { X509Possession x509Possession) throws IOException { T13CertificateVerifyMessage cvm = new T13CertificateVerifyMessage(shc, x509Possession); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced server CertificateVerify handshake message", cvm); } @@ -1130,7 +1130,7 @@ final class CertificateVerify { X509Possession x509Possession) throws IOException { T13CertificateVerifyMessage cvm = new T13CertificateVerifyMessage(chc, x509Possession); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced client CertificateVerify handshake message", cvm); } @@ -1173,7 +1173,7 @@ final class CertificateVerify { T13CertificateVerifyMessage cvm = new T13CertificateVerifyMessage(hc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming CertificateVerify handshake message", cvm); } diff --git a/src/java.base/share/classes/sun/security/ssl/ChangeCipherSpec.java b/src/java.base/share/classes/sun/security/ssl/ChangeCipherSpec.java index 4ea61161c1d..d3eac8f13af 100644 --- a/src/java.base/share/classes/sun/security/ssl/ChangeCipherSpec.java +++ b/src/java.base/share/classes/sun/security/ssl/ChangeCipherSpec.java @@ -108,7 +108,7 @@ final class ChangeCipherSpec { ") and protocol version (" + hc.negotiatedProtocol + ")"); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced ChangeCipherSpec message"); } @@ -142,7 +142,7 @@ final class ChangeCipherSpec { throw tc.fatal(Alert.UNEXPECTED_MESSAGE, "Malformed or unexpected ChangeCipherSpec message"); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Consuming ChangeCipherSpec message"); } @@ -237,7 +237,7 @@ final class ChangeCipherSpec { throw tc.fatal(Alert.UNEXPECTED_MESSAGE, "Malformed or unexpected ChangeCipherSpec message"); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Consuming ChangeCipherSpec message"); } diff --git a/src/java.base/share/classes/sun/security/ssl/ClientHello.java b/src/java.base/share/classes/sun/security/ssl/ClientHello.java index c9432ea3979..421673d625d 100644 --- a/src/java.base/share/classes/sun/security/ssl/ClientHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ClientHello.java @@ -430,7 +430,7 @@ final class ClientHello { if (!session.isRejoinable()) { session = null; - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, the session is not rejoinable"); @@ -443,7 +443,7 @@ final class ClientHello { sessionSuite = session.getSuite(); if (!chc.isNegotiable(sessionSuite)) { session = null; - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, unavailable session cipher suite"); @@ -456,7 +456,7 @@ final class ClientHello { sessionVersion = session.getProtocolVersion(); if (!chc.isNegotiable(sessionVersion)) { session = null; - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, unavailable protocol version"); @@ -513,7 +513,7 @@ final class ClientHello { String sessionIdentityAlg = session.getIdentificationProtocol(); if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest("Can't resume, endpoint id" + " algorithm does not match, requested: " + @@ -524,7 +524,7 @@ final class ClientHello { } if (session != null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest("Try resuming session", session); } @@ -547,7 +547,7 @@ final class ClientHello { cipherSuites = List.of(sessionSuite); } - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "No new session is allowed, so try to resume " + @@ -634,7 +634,7 @@ final class ClientHello { SSLHandshake.CLIENT_HELLO, chc.activeProtocols); chm.extensions.produce(chc, extTypes); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced ClientHello handshake message", chm); } @@ -700,7 +700,7 @@ final class ClientHello { // // The HelloVerifyRequest consumer should have updated the // ClientHello handshake message with cookie. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced ClientHello(cookie) handshake message", chc.initialClientHelloMsg); @@ -734,7 +734,7 @@ final class ClientHello { // TLS 1.3 // The HelloRetryRequest consumer should have updated the // ClientHello handshake message with cookie. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced ClientHello(HRR) handshake message", chc.initialClientHelloMsg); @@ -790,7 +790,7 @@ final class ClientHello { ClientHelloMessage chm = new ClientHelloMessage(shc, message, enabledExtensions); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Consuming ClientHello handshake message", chm); } @@ -820,7 +820,7 @@ final class ClientHello { negotiateProtocol(context, clientHello.clientVersion); } context.negotiatedProtocol = negotiatedProtocol; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Negotiated protocol version: " + negotiatedProtocol.name); } @@ -980,7 +980,7 @@ final class ClientHello { boolean resumingSession = (previous != null) && previous.isRejoinable(); if (!resumingSession) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, " + @@ -993,7 +993,7 @@ final class ClientHello { previous.getProtocolVersion(); if (sessionProtocol != shc.negotiatedProtocol) { resumingSession = false; - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, not the same protocol version"); @@ -1008,7 +1008,7 @@ final class ClientHello { previous.getPeerPrincipal(); } catch (SSLPeerUnverifiedException e) { resumingSession = false; - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, " + @@ -1023,7 +1023,7 @@ final class ClientHello { if ((!shc.isNegotiable(suite)) || (!clientHello.cipherSuites.contains(suite))) { resumingSession = false; - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, " + @@ -1039,7 +1039,7 @@ final class ClientHello { String sessionIdentityAlg = previous.getIdentificationProtocol(); if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest("Can't resume, endpoint id" + " algorithm does not match, requested: " + @@ -1054,7 +1054,7 @@ final class ClientHello { shc.isResumption = resumingSession; shc.resumingSession = resumingSession ? previous : null; - if (!resumingSession && SSLLogger.isOn && + if (!resumingSession && SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Session not resumed."); } @@ -1321,7 +1321,7 @@ final class ClientHello { boolean resumingSession = (previous != null) && previous.isRejoinable(); if (!resumingSession) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, " + @@ -1334,7 +1334,7 @@ final class ClientHello { previous.getProtocolVersion(); if (sessionProtocol != shc.negotiatedProtocol) { resumingSession = false; - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, not the same protocol version"); @@ -1350,7 +1350,7 @@ final class ClientHello { previous.getPeerPrincipal(); } catch (SSLPeerUnverifiedException e) { resumingSession = false; - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, " + @@ -1365,7 +1365,7 @@ final class ClientHello { if ((!shc.isNegotiable(suite)) || (!clientHello.cipherSuites.contains(suite))) { resumingSession = false; - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, " + diff --git a/src/java.base/share/classes/sun/security/ssl/CookieExtension.java b/src/java.base/share/classes/sun/security/ssl/CookieExtension.java index d54a1a3e63d..2c22dd121ba 100644 --- a/src/java.base/share/classes/sun/security/ssl/CookieExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/CookieExtension.java @@ -117,7 +117,7 @@ public class CookieExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(SSLExtension.CH_COOKIE)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable cookie extension"); } @@ -154,7 +154,7 @@ public class CookieExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(SSLExtension.CH_COOKIE)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable cookie extension"); } @@ -218,7 +218,7 @@ public class CookieExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(SSLExtension.HRR_COOKIE)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable cookie extension"); } @@ -253,7 +253,7 @@ public class CookieExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(SSLExtension.HRR_COOKIE)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable cookie extension"); } @@ -280,7 +280,7 @@ public class CookieExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(SSLExtension.HRR_COOKIE)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable cookie extension"); } diff --git a/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java index fb5d6feef55..53f9896a3e4 100644 --- a/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java @@ -187,7 +187,7 @@ final class DHClientKeyExchange { chc.handshakePossessions.add(dhePossession); DHClientKeyExchangeMessage ckem = new DHClientKeyExchangeMessage(chc); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced DH ClientKeyExchange handshake message", ckem); } @@ -268,7 +268,7 @@ final class DHClientKeyExchange { DHClientKeyExchangeMessage ckem = new DHClientKeyExchangeMessage(shc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming DH ClientKeyExchange handshake message", ckem); } diff --git a/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java index 2df62d50fb8..744ff59f402 100644 --- a/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java @@ -481,7 +481,7 @@ final class DHServerKeyExchange { ServerHandshakeContext shc = (ServerHandshakeContext)context; DHServerKeyExchangeMessage skem = new DHServerKeyExchangeMessage(shc); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced DH ServerKeyExchange handshake message", skem); } @@ -512,7 +512,7 @@ final class DHServerKeyExchange { DHServerKeyExchangeMessage skem = new DHServerKeyExchangeMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming DH ServerKeyExchange handshake message", skem); } diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java index 4e82fd25a7b..e880f36e846 100644 --- a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java @@ -125,7 +125,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { return null; } - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw read", packet); } @@ -150,7 +150,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { int contentLen = ((packet.get() & 0xFF) << 8) | (packet.get() & 0xFF); // pos: 11, 12 - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine("READ: " + ProtocolVersion.nameOf(majorVersion, minorVersion) + " " + ContentType.nameOf(contentType) + ", length = " + @@ -162,7 +162,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { if (this.readEpoch > recordEpoch) { // Reset the position of the packet buffer. packet.position(recLim); - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine("READ: discard this old record", recordEnS); } return null; @@ -181,7 +181,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { packet.position(recLim); - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("Premature record (epoch), discard it."); } @@ -223,7 +223,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { plaintextFragment = plaintext.fragment; contentType = plaintext.contentType; } catch (GeneralSecurityException gse) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("Discard invalid record: " + gse); } @@ -241,7 +241,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // Cleanup the handshake reassembler if necessary. if ((reassembler != null) && (reassembler.handshakeEpoch < recordEpoch)) { - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("Cleanup the handshake reassembler"); } @@ -273,7 +273,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { if (hsFrag == null) { // invalid, discard this record - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Invalid handshake message, discard it."); } @@ -296,7 +296,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { return pt == null ? null : new Plaintext[] { pt }; } - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("The reassembler is not initialized yet."); } @@ -356,7 +356,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { int remaining = plaintextFragment.remaining(); if (remaining < handshakeHeaderSize) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("Discard invalid record: " + "too small record to hold a handshake fragment"); } @@ -368,7 +368,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // Fail fast for unknown handshake message. byte handshakeType = plaintextFragment.get(); // pos: 0 if (!SSLHandshake.isKnown(handshakeType)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("Discard invalid record: " + "unknown handshake type size, Handshake.msg_type = " + (handshakeType & 0xFF)); @@ -404,7 +404,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { ((plaintextFragment.get() & 0xFF) << 8) | (plaintextFragment.get() & 0xFF); // pos: 9-11 if ((remaining - handshakeHeaderSize) < fragmentLength) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("Discard invalid record: " + "not a complete handshake fragment in the record"); } @@ -748,7 +748,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // It's OK to discard retransmission as the handshake hash // is computed as if each handshake message had been sent // as a single fragment. - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("Have got the full message, discard it."); } @@ -769,7 +769,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // The ranges SHOULD NOT overlap. if (hole.offset > hsf.fragmentOffset || hole.limit < fragmentLimit) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("Discard invalid record: " + "handshake fragment ranges are overlapping"); } @@ -837,7 +837,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { } // Read the random (32 bytes) if (fragmentData.remaining() < 32) { - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("Rejected client hello fragment (bad random len) " + "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength); } @@ -861,7 +861,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // Cookie byte[] cookie = Record.getBytes8(fragmentData); if (firstHello && cookie.length != 0) { - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("Rejected initial client hello fragment (bad cookie len) " + "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength); } @@ -897,7 +897,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { } } } catch (IOException ioe) { - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("Rejected client hello fragment " + "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength); } @@ -1029,7 +1029,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { int previousEpoch = nextRecordEpoch - 1; if (rf.recordEpoch < previousEpoch) { // Too old to use, discard this record. - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Too old epoch to use this record, discard it."); } @@ -1075,7 +1075,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { if (!isDesired) { // Too old to use, discard this retransmitted record - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Too old retransmission to use, discard it."); } @@ -1088,7 +1088,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // Previously disordered record for the current epoch. // // Should have been retransmitted. Discard this record. - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Lagging behind record (sequence), discard it."); } @@ -1126,7 +1126,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { Plaintext acquirePlaintext() throws SSLProtocolException { if (bufferedFragments.isEmpty()) { - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("No received handshake messages"); } return null; @@ -1147,7 +1147,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // Reset the next handshake flight. resetHandshakeFlight(precedingFlight); - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("Received a retransmission flight."); } @@ -1159,7 +1159,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { } if (!flightIsReady) { - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "The handshake flight is not ready to use: " + handshakeFlight.handshakeType); @@ -1244,7 +1244,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { if (readEpoch != rFrag.recordEpoch) { if (readEpoch > rFrag.recordEpoch) { // discard old records - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Discard old buffered ciphertext fragments."); } @@ -1256,7 +1256,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { flightIsReady = false; } - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Not yet ready to decrypt the cached fragments."); } @@ -1273,7 +1273,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { plaintextFragment = plaintext.fragment; rFrag.contentType = plaintext.contentType; } catch (GeneralSecurityException gse) { - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("Discard invalid record: ", gse); } @@ -1295,7 +1295,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { if (hsFrag == null) { // invalid, discard this record - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Invalid handshake fragment, discard it", plaintextFragment); @@ -1446,7 +1446,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { if (expectCCSFlight) { // Have the ChangeCipherSpec/Finished flight been received? boolean isReady = hasFinishedMessage(); - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Has the final flight been received? " + isReady); } @@ -1454,7 +1454,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { return isReady; } - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("No flight is received yet."); } @@ -1467,7 +1467,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // single handshake message flight boolean isReady = hasCompleted(flightType); - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Is the handshake message completed? " + isReady); } @@ -1481,7 +1481,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { if (flightType == SSLHandshake.SERVER_HELLO.id) { // Firstly, check the first flight handshake message. if (!hasCompleted(flightType)) { - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "The ServerHello message is not completed yet."); } @@ -1493,7 +1493,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // an abbreviated handshake // if (hasFinishedMessage()) { - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("It's an abbreviated handshake."); } @@ -1507,7 +1507,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { SSLHandshake.SERVER_HELLO_DONE.id); if ((holes == null) || !holes.isEmpty()) { // Not yet got the final message of the flight. - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Not yet got the ServerHelloDone message"); } @@ -1519,7 +1519,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { boolean isReady = hasCompleted(bufferedFragments, handshakeFlight.minMessageSeq, handshakeFlight.maxMessageSeq); - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Is the ServerHello flight (message " + handshakeFlight.minMessageSeq + "-" + @@ -1542,7 +1542,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // Firstly, check the first flight handshake message. if (!hasCompleted(flightType)) { - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "The ClientKeyExchange or client Certificate " + "message is not completed yet."); @@ -1556,7 +1556,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { if (needClientVerify(bufferedFragments) && !hasCompleted(SSLHandshake.CERTIFICATE_VERIFY.id)) { - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Not yet have the CertificateVerify message"); } @@ -1567,7 +1567,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { if (!hasFinishedMessage()) { // not yet have the ChangeCipherSpec/Finished messages - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Not yet have the ChangeCipherSpec and " + "Finished messages"); @@ -1580,7 +1580,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { boolean isReady = hasCompleted(bufferedFragments, handshakeFlight.minMessageSeq, handshakeFlight.maxMessageSeq); - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Is the ClientKeyExchange flight (message " + handshakeFlight.minMessageSeq + "-" + @@ -1594,7 +1594,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // // Otherwise, need to receive more handshake messages. // - if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("Need to receive more handshake messages"); } diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java index 691ac32c26b..162dbb58eec 100644 --- a/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java @@ -92,7 +92,7 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { void changeWriteCiphers(SSLWriteCipher writeCipher, boolean useChangeCipherSpec) { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "change_cipher_spec message"); } @@ -120,7 +120,7 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { @Override void encodeAlert(byte level, byte description) { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "alert message: " + Alert.nameOf(description)); } @@ -137,7 +137,7 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { @Override void encodeChangeCipherSpec() { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "change_cipher_spec message"); } @@ -154,7 +154,7 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { void encodeHandshake(byte[] source, int offset, int length) { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "handshake message", ByteBuffer.wrap(source, offset, length)); @@ -179,14 +179,14 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException { if (isClosed) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "application data or cached messages"); } return null; } else if (isCloseWaiting) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "application data"); } @@ -201,7 +201,7 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { ByteBuffer destination) throws IOException { if (writeCipher.authenticator.seqNumOverflow()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine( "sequence number extremely close to overflow " + "(2^64-1 packets). Closing connection."); @@ -269,7 +269,7 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { destination.limit(destination.position()); destination.position(dstContent); - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "WRITE: " + protocolVersion.name + " " + ContentType.APPLICATION_DATA.name + @@ -282,7 +282,7 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { dstPos, dstLim, headerSize, protocolVersion); - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { ByteBuffer temporary = destination.duplicate(); temporary.limit(temporary.position()); temporary.position(dstPos); @@ -497,7 +497,7 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { dstBuf.limit(dstBuf.position()); dstBuf.position(dstContent); - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "WRITE: " + protocolVersion.name + " " + ContentType.nameOf(memo.contentType) + @@ -511,7 +511,7 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { ProtocolVersion.valueOf(memo.majorVersion, memo.minorVersion)); - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { ByteBuffer temporary = dstBuf.duplicate(); temporary.limit(temporary.position()); temporary.position(dstPos); diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java index e1c1b1377ad..a626f6f34d0 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java @@ -199,7 +199,7 @@ final class ECDHClientKeyExchange { ECDHClientKeyExchangeMessage cke = new ECDHClientKeyExchangeMessage( chc, sslPossession.encode()); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced ECDH ClientKeyExchange handshake message", cke); } @@ -308,7 +308,7 @@ final class ECDHClientKeyExchange { // parse either handshake message containing either EC/XEC. ECDHClientKeyExchangeMessage cke = new ECDHClientKeyExchangeMessage(shc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming ECDH ClientKeyExchange handshake message", cke); } @@ -397,7 +397,7 @@ final class ECDHClientKeyExchange { new ECDHClientKeyExchangeMessage( chc, sslPossession.encode()); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced ECDHE ClientKeyExchange handshake message", cke); } @@ -490,7 +490,7 @@ final class ECDHClientKeyExchange { // parse the EC/XEC handshake message ECDHClientKeyExchangeMessage cke = new ECDHClientKeyExchangeMessage(shc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming ECDHE ClientKeyExchange handshake message", cke); } diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java index b31c0ba9cb9..a02a8438163 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java @@ -489,7 +489,7 @@ final class ECDHServerKeyExchange { ServerHandshakeContext shc = (ServerHandshakeContext)context; ECDHServerKeyExchangeMessage skem = new ECDHServerKeyExchangeMessage(shc); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced ECDH ServerKeyExchange handshake message", skem); } @@ -522,7 +522,7 @@ final class ECDHServerKeyExchange { // AlgorithmConstraints are checked during decoding ECDHServerKeyExchangeMessage skem = new ECDHServerKeyExchangeMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming ECDH ServerKeyExchange handshake message", skem); } diff --git a/src/java.base/share/classes/sun/security/ssl/ECPointFormatsExtension.java b/src/java.base/share/classes/sun/security/ssl/ECPointFormatsExtension.java index 580e1d416de..72b7c950374 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECPointFormatsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/ECPointFormatsExtension.java @@ -171,7 +171,7 @@ final class ECPointFormatsExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(CH_EC_POINT_FORMATS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable ec_point_formats extension"); } @@ -193,7 +193,7 @@ final class ECPointFormatsExtension { return extData; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Need no ec_point_formats extension"); } @@ -221,7 +221,7 @@ final class ECPointFormatsExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(CH_EC_POINT_FORMATS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable ec_point_formats extension"); } diff --git a/src/java.base/share/classes/sun/security/ssl/EncryptedExtensions.java b/src/java.base/share/classes/sun/security/ssl/EncryptedExtensions.java index d1975b5caa4..b5be927f0aa 100644 --- a/src/java.base/share/classes/sun/security/ssl/EncryptedExtensions.java +++ b/src/java.base/share/classes/sun/security/ssl/EncryptedExtensions.java @@ -134,7 +134,7 @@ final class EncryptedExtensions { SSLHandshake.ENCRYPTED_EXTENSIONS, shc.negotiatedProtocol); eem.extensions.produce(shc, extTypes); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced EncryptedExtensions message", eem); } @@ -168,7 +168,7 @@ final class EncryptedExtensions { EncryptedExtensionsMessage eem = new EncryptedExtensionsMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming EncryptedExtensions handshake message", eem); } diff --git a/src/java.base/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java b/src/java.base/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java index ff4694c8c7c..6bacbfbd1d8 100644 --- a/src/java.base/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java @@ -119,7 +119,7 @@ final class ExtendedMasterSecretExtension { if (!chc.sslConfig.isAvailable(CH_EXTENDED_MASTER_SECRET) || !SSLConfiguration.useExtendedMasterSecret || !chc.conContext.protocolVersion.useTLS10PlusSpec()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extended_master_secret extension"); } @@ -162,7 +162,7 @@ final class ExtendedMasterSecretExtension { if (!shc.sslConfig.isAvailable(CH_EXTENDED_MASTER_SECRET) || !SSLConfiguration.useExtendedMasterSecret || !shc.negotiatedProtocol.useTLS10PlusSpec()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Ignore unavailable extension: " + CH_EXTENDED_MASTER_SECRET.name); } @@ -182,7 +182,7 @@ final class ExtendedMasterSecretExtension { // with a full handshake. shc.isResumption = false; shc.resumingSession = null; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "abort session resumption which did not use " + "Extended Master Secret extension"); @@ -213,7 +213,7 @@ final class ExtendedMasterSecretExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(CH_EXTENDED_MASTER_SECRET) || !SSLConfiguration.useExtendedMasterSecret) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Ignore unavailable extension: " + CH_EXTENDED_MASTER_SECRET.name); } @@ -252,7 +252,7 @@ final class ExtendedMasterSecretExtension { } else { // Otherwise, continue with a full handshake. shc.isResumption = false; shc.resumingSession = null; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "abort session resumption, " + "missing Extended Master Secret extension"); diff --git a/src/java.base/share/classes/sun/security/ssl/Finished.java b/src/java.base/share/classes/sun/security/ssl/Finished.java index 04fe61760d0..4238ced8f01 100644 --- a/src/java.base/share/classes/sun/security/ssl/Finished.java +++ b/src/java.base/share/classes/sun/security/ssl/Finished.java @@ -390,7 +390,7 @@ final class Finished { // Change write cipher and delivery ChangeCipherSpec message. ChangeCipherSpec.t10Producer.produce(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced client Finished handshake message", fm); } @@ -453,7 +453,7 @@ final class Finished { // Change write cipher and delivery ChangeCipherSpec message. ChangeCipherSpec.t10Producer.produce(shc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced server Finished handshake message", fm); } @@ -542,7 +542,7 @@ final class Finished { private void onConsumeFinished(ClientHandshakeContext chc, ByteBuffer message) throws IOException { FinishedMessage fm = new FinishedMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming server Finished handshake message", fm); } @@ -602,7 +602,7 @@ final class Finished { } FinishedMessage fm = new FinishedMessage(shc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming client Finished handshake message", fm); } @@ -681,7 +681,7 @@ final class Finished { chc.handshakeHash.update(); FinishedMessage fm = new FinishedMessage(chc); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced client Finished handshake message", fm); } @@ -778,7 +778,7 @@ final class Finished { shc.handshakeHash.update(); FinishedMessage fm = new FinishedMessage(shc); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced server Finished handshake message", fm); } @@ -930,7 +930,7 @@ final class Finished { } FinishedMessage fm = new FinishedMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming server Finished handshake message", fm); } @@ -1073,7 +1073,7 @@ final class Finished { } FinishedMessage fm = new FinishedMessage(shc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming client Finished handshake message", fm); } 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 8455ddfc65d..a5f340d5203 100644 --- a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java +++ b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java @@ -284,14 +284,14 @@ abstract class HandshakeContext implements ConnectionContext { found = true; break; } - } else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + } else if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "Ignore unsupported cipher suite: " + suite + " for " + protocol.name); } } - if (!found && (SSLLogger.isOn) && SSLLogger.isOn("handshake")) { + if (!found && (SSLLogger.isOn()) && SSLLogger.isOn("handshake")) { SSLLogger.fine( "No available cipher suite for " + protocol.name); } @@ -335,7 +335,7 @@ abstract class HandshakeContext implements ConnectionContext { } if (!isSupported && - SSLLogger.isOn && SSLLogger.isOn("verbose")) { + SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.finest( "Ignore unsupported cipher suite: " + suite); } @@ -556,7 +556,7 @@ abstract class HandshakeContext implements ConnectionContext { cachedStatus.put(groupType, groupAvailable); if (!groupAvailable && - SSLLogger.isOn && SSLLogger.isOn("verbose")) { + SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine( "No activated named group in " + groupType); } @@ -570,13 +570,13 @@ abstract class HandshakeContext implements ConnectionContext { } } - if (!retval && SSLLogger.isOn && SSLLogger.isOn("verbose")) { + if (!retval && SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("No active named group(s), ignore " + suite); } return retval; - } else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { + } else if (SSLLogger.isOn() && SSLLogger.isOn("verbose")) { SSLLogger.fine("Ignore disabled cipher suite: " + suite); } diff --git a/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java b/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java index 61936442502..2a05881180d 100644 --- a/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java +++ b/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java @@ -61,7 +61,7 @@ public class HandshakeOutStream extends ByteArrayOutputStream { if (!outputRecord.isClosed()) { outputRecord.encodeHandshake(buf, 0, count); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "handshake messages", ByteBuffer.wrap(buf, 0, count)); } diff --git a/src/java.base/share/classes/sun/security/ssl/HelloRequest.java b/src/java.base/share/classes/sun/security/ssl/HelloRequest.java index f4da66b5dd3..39464992db5 100644 --- a/src/java.base/share/classes/sun/security/ssl/HelloRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/HelloRequest.java @@ -101,7 +101,7 @@ final class HelloRequest { ServerHandshakeContext shc = (ServerHandshakeContext)context; HelloRequestMessage hrm = new HelloRequestMessage(shc); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced HelloRequest handshake message", hrm); } @@ -137,7 +137,7 @@ final class HelloRequest { ServerHandshakeContext shc = (ServerHandshakeContext)context; HelloRequestMessage hrm = new HelloRequestMessage(shc); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced HelloRequest handshake message", hrm); } @@ -177,7 +177,7 @@ final class HelloRequest { // be sent by the server at any time. Please don't clean up this // handshake consumer. HelloRequestMessage hrm = new HelloRequestMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming HelloRequest handshake message", hrm); } @@ -190,7 +190,7 @@ final class HelloRequest { } if (!chc.conContext.secureRenegotiation) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Continue with insecure renegotiation"); } @@ -206,7 +206,7 @@ final class HelloRequest { // SSLHandshake.CLIENT_HELLO.produce(context, hrm); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore HelloRequest, handshaking is in progress"); } diff --git a/src/java.base/share/classes/sun/security/ssl/HelloVerifyRequest.java b/src/java.base/share/classes/sun/security/ssl/HelloVerifyRequest.java index f28ae16de88..8d3f1048c91 100644 --- a/src/java.base/share/classes/sun/security/ssl/HelloVerifyRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/HelloVerifyRequest.java @@ -140,7 +140,7 @@ final class HelloVerifyRequest { HelloVerifyRequestMessage hvrm = new HelloVerifyRequestMessage(shc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced HelloVerifyRequest handshake message", hvrm); } @@ -197,7 +197,7 @@ final class HelloVerifyRequest { HelloVerifyRequestMessage hvrm = new HelloVerifyRequestMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming HelloVerifyRequest handshake message", hvrm); } diff --git a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java index 98e4693e917..8d785f7515a 100644 --- a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java @@ -90,7 +90,7 @@ final class KeyShareExtension { Record.putInt16(m, namedGroupId); Record.putBytes16(m, keyExchange); } catch (IOException ioe) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Unlikely IOException", ioe); } @@ -222,7 +222,7 @@ final class KeyShareExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(SSLExtension.CH_KEY_SHARE)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable key_share extension"); } @@ -237,7 +237,7 @@ final class KeyShareExtension { namedGroups = chc.clientRequestedNamedGroups; if (namedGroups == null || namedGroups.isEmpty()) { // No supported groups. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Ignore key_share extension, no supported groups"); } @@ -287,7 +287,7 @@ final class KeyShareExtension { NamedGroup ng) { SSLKeyExchange ke = SSLKeyExchange.valueOf(ng); if (ke == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "No key exchange for named group " + ng.name); } @@ -323,7 +323,7 @@ final class KeyShareExtension { ServerHandshakeContext shc = (ServerHandshakeContext)context; if (shc.handshakeExtensions.containsKey(SSLExtension.CH_KEY_SHARE)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "The key_share extension has been loaded"); } @@ -332,7 +332,7 @@ final class KeyShareExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(SSLExtension.CH_KEY_SHARE)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable key_share extension"); } @@ -346,7 +346,7 @@ final class KeyShareExtension { NamedGroup ng = NamedGroup.valueOf(entry.namedGroupId); if (ng == null || !NamedGroup.isActivatable(shc.sslConfig, shc.algorithmConstraints, ng)) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unsupported named group: " + @@ -364,7 +364,7 @@ final class KeyShareExtension { if (!shc.algorithmConstraints.permits( EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), namedGroupCredentials.getPublicKey())) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "key share entry of " + ng + " does not " + @@ -379,7 +379,7 @@ final class KeyShareExtension { credentials.add(kaCred); } } catch (GeneralSecurityException ex) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Cannot decode named group: " + NamedGroup.nameOf(entry.namedGroupId)); @@ -522,7 +522,7 @@ final class KeyShareExtension { SSLExtension.CH_KEY_SHARE); if (kss == null) { // Unlikely, no key_share extension requested. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Ignore, no client key_share extension"); } @@ -531,7 +531,7 @@ final class KeyShareExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(SSLExtension.SH_KEY_SHARE)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Ignore, no available server key_share extension"); } @@ -542,7 +542,7 @@ final class KeyShareExtension { if ((shc.handshakeCredentials == null) || shc.handshakeCredentials.isEmpty()) { // Unlikely, HelloRetryRequest should be used earlier. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "No available client key share entries"); } @@ -562,7 +562,7 @@ final class KeyShareExtension { SSLKeyExchange ke = SSLKeyExchange.valueOf(ng); if (ke == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "No key exchange for named group " + ng.name); } @@ -597,7 +597,7 @@ final class KeyShareExtension { if (keyShare == null) { // Unlikely, HelloRetryRequest should be used instead earlier. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "No available server key_share extension"); } @@ -708,7 +708,7 @@ final class KeyShareExtension { ClientHandshakeContext chc = (ClientHandshakeContext)context; // Cannot use the previous requested key shares anymore. - if (SSLLogger.isOn && SSLLogger.isOn("handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("handshake")) { SSLLogger.fine( "No key_share extension in ServerHello, " + "cleanup the key shares if necessary"); @@ -801,7 +801,7 @@ final class KeyShareExtension { for (NamedGroup ng : shc.clientRequestedNamedGroups) { if (NamedGroup.isActivatable(shc.sslConfig, shc.algorithmConstraints, ng)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "HelloRetryRequest selected named group: " + ng.name); diff --git a/src/java.base/share/classes/sun/security/ssl/KeyUpdate.java b/src/java.base/share/classes/sun/security/ssl/KeyUpdate.java index 2b17c7406a3..4e5a9683079 100644 --- a/src/java.base/share/classes/sun/security/ssl/KeyUpdate.java +++ b/src/java.base/share/classes/sun/security/ssl/KeyUpdate.java @@ -191,7 +191,7 @@ final class KeyUpdate { // The consuming happens in client side only. PostHandshakeContext hc = (PostHandshakeContext)context; KeyUpdateMessage km = new KeyUpdateMessage(hc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming KeyUpdate post-handshake message", km); } @@ -235,7 +235,7 @@ final class KeyUpdate { rc.baseSecret = nplus1; hc.conContext.inputRecord.changeReadCiphers(rc); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("KeyUpdate: read key updated"); } } catch (GeneralSecurityException gse) { @@ -276,7 +276,7 @@ final class KeyUpdate { return null; } KeyUpdateMessage km = (KeyUpdateMessage)message; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced KeyUpdate post-handshake message", km); } @@ -328,7 +328,7 @@ final class KeyUpdate { // changeWriteCiphers() implementation. wc.baseSecret = nplus1; hc.conContext.outputRecord.changeWriteCiphers(wc, km.status.id); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("KeyUpdate: write key updated"); } diff --git a/src/java.base/share/classes/sun/security/ssl/MaxFragExtension.java b/src/java.base/share/classes/sun/security/ssl/MaxFragExtension.java index a07e81be914..25500c7ac57 100644 --- a/src/java.base/share/classes/sun/security/ssl/MaxFragExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/MaxFragExtension.java @@ -176,7 +176,7 @@ final class MaxFragExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(CH_MAX_FRAGMENT_LENGTH)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable max_fragment_length extension"); } @@ -213,7 +213,7 @@ final class MaxFragExtension { } else { // log and ignore, no MFL extension. chc.maxFragmentLength = -1; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "No available max_fragment_length extension can " + "be used for fragment size of " + @@ -243,7 +243,7 @@ final class MaxFragExtension { ServerHandshakeContext shc = (ServerHandshakeContext)context; if (!shc.sslConfig.isAvailable(CH_MAX_FRAGMENT_LENGTH)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable max_fragment_length extension"); } @@ -288,7 +288,7 @@ final class MaxFragExtension { MaxFragLenSpec spec = (MaxFragLenSpec) shc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH); if (spec == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "Ignore unavailable max_fragment_length extension"); } @@ -305,7 +305,7 @@ final class MaxFragExtension { // For better interoperability, abort the maximum // fragment length negotiation, rather than terminate // the connection with a fatal alert. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Abort the maximum fragment length negotiation, " + "may overflow the maximum packet size limit."); @@ -413,7 +413,7 @@ final class MaxFragExtension { // For better interoperability, abort the maximum // fragment length negotiation, rather than terminate // the connection with a fatal alert. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Abort the maximum fragment length negotiation, " + "may overflow the maximum packet size limit."); @@ -455,7 +455,7 @@ final class MaxFragExtension { MaxFragLenSpec spec = (MaxFragLenSpec) shc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH); if (spec == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "Ignore unavailable max_fragment_length extension"); } @@ -472,7 +472,7 @@ final class MaxFragExtension { // For better interoperability, abort the maximum // fragment length negotiation, rather than terminate // the connection with a fatal alert. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Abort the maximum fragment length negotiation, " + "may overflow the maximum packet size limit."); @@ -578,7 +578,7 @@ final class MaxFragExtension { // For better interoperability, abort the maximum // fragment length negotiation, rather than terminate // the connection with a fatal alert. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Abort the maximum fragment length negotiation, " + "may overflow the maximum packet size limit."); diff --git a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java index 46280a05355..0c708b194cb 100644 --- a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java +++ b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java @@ -273,7 +273,7 @@ enum NamedGroup { | NoSuchAlgorithmException exp) { if (namedGroupSpec != NamedGroupSpec.NAMED_GROUP_XDH) { mediator = false; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "No AlgorithmParameters for " + name, exp); } @@ -294,7 +294,7 @@ enum NamedGroup { // AlgorithmParameters.getInstance(name); } catch (NoSuchAlgorithmException nsae) { mediator = false; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "No AlgorithmParameters for " + name, nsae); } @@ -382,7 +382,7 @@ enum NamedGroup { for (String ss : namedGroups) { NamedGroup ng = NamedGroup.nameOf(ss); if (ng == null || !ng.isAvailable) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Ignore the named group (" + ss @@ -811,7 +811,7 @@ enum NamedGroup { } if (groupList.isEmpty() && - SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("No default named groups"); } } diff --git a/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java b/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java index 4c879e0dc4d..89b0a72bb32 100644 --- a/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java +++ b/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java @@ -202,7 +202,7 @@ final class NewSessionTicket { this.ticket = Record.getBytes16(m); if (ticket.length == 0) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "No ticket in the NewSessionTicket handshake message"); } @@ -329,7 +329,7 @@ final class NewSessionTicket { if (hc instanceof ServerHandshakeContext) { // Is this session resumable? if (!hc.handshakeSession.isRejoinable()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("No session ticket produced: " + "session is not resumable"); } @@ -347,7 +347,7 @@ final class NewSessionTicket { SSLExtension.PSK_KEY_EXCHANGE_MODES); if (pkemSpec == null || !pkemSpec.contains(PskKeyExchangeMode.PSK_DHE_KE)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("No session ticket produced: " + "client does not support psk_dhe_ke"); } @@ -358,7 +358,7 @@ final class NewSessionTicket { // Check if we have sent a PSK already, then we know it is // using an allowable PSK exchange key mode. if (!hc.handshakeSession.isPSKable()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("No session ticket produced: " + "No session ticket allowed in this session"); } @@ -372,7 +372,7 @@ final class NewSessionTicket { hc.sslContext.engineGetServerSessionContext(); int sessionTimeoutSeconds = sessionCache.getSessionTimeout(); if (sessionTimeoutSeconds > MAX_TICKET_LIFETIME) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("No session ticket produced: " + "session timeout is too long"); } @@ -459,7 +459,7 @@ final class NewSessionTicket { if (!nstm.isValid()) { hc.statelessResumption = false; } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced NewSessionTicket stateless " + "post-handshake message", nstm); } @@ -474,7 +474,7 @@ final class NewSessionTicket { sessionCache.getSessionTimeout(), hc.sslContext.getSecureRandom(), nonce, newId.getId()); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced NewSessionTicket " + "post-handshake message", nstm); } @@ -488,7 +488,7 @@ final class NewSessionTicket { return nstm; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("No NewSessionTicket created"); } @@ -526,7 +526,7 @@ final class NewSessionTicket { shc.sslContext.engineGetServerSessionContext(); int sessionTimeoutSeconds = sessionCache.getSessionTimeout(); if (sessionTimeoutSeconds > MAX_TICKET_LIFETIME) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Session timeout is too long. No ticket sent."); } @@ -540,7 +540,7 @@ final class NewSessionTicket { NewSessionTicketMessage nstm = new T12NewSessionTicketMessage(shc, sessionTimeoutSeconds, new SessionTicketSpec().encrypt(shc, sessionCopy)); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced NewSessionTicket stateless handshake message", nstm); @@ -579,7 +579,7 @@ final class NewSessionTicket { HandshakeContext hc = (HandshakeContext)context; NewSessionTicketMessage nstm = new T13NewSessionTicketMessage(hc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming NewSessionTicket message", nstm); } @@ -590,7 +590,7 @@ final class NewSessionTicket { // discard tickets with timeout 0 if (nstm.ticketLifetime <= 0 || nstm.ticketLifetime > MAX_TICKET_LIFETIME) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Discarding NewSessionTicket with lifetime " + nstm.ticketLifetime, nstm); @@ -599,7 +599,7 @@ final class NewSessionTicket { } if (sessionCache.getSessionTimeout() > MAX_TICKET_LIFETIME) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Session cache lifetime is too long. " + "Discarding ticket."); @@ -611,7 +611,7 @@ final class NewSessionTicket { SecretKey resumptionMasterSecret = sessionToSave.getResumptionMasterSecret(); if (resumptionMasterSecret == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Session has no resumption master secret. " + "Ignoring ticket."); @@ -637,7 +637,7 @@ final class NewSessionTicket { sessionCopy.setPskIdentity(nstm.ticket); sessionCache.put(sessionCopy, sessionCopy.isPSK()); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("MultiNST PSK (Server): " + Utilities.toHexString(Arrays.copyOf(nstm.ticket, 16))); } @@ -665,7 +665,7 @@ final class NewSessionTicket { NewSessionTicketMessage nstm = new T12NewSessionTicketMessage(hc, message); if (nstm.ticket.length == 0) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("NewSessionTicket ticket was empty"); } return; @@ -674,7 +674,7 @@ final class NewSessionTicket { // discard tickets with timeout 0 if (nstm.ticketLifetime <= 0 || nstm.ticketLifetime > MAX_TICKET_LIFETIME) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Discarding NewSessionTicket with lifetime " + nstm.ticketLifetime, nstm); @@ -686,7 +686,7 @@ final class NewSessionTicket { hc.sslContext.engineGetClientSessionContext(); if (sessionCache.getSessionTimeout() > MAX_TICKET_LIFETIME) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Session cache lifetime is too long. " + "Discarding ticket."); @@ -695,7 +695,7 @@ final class NewSessionTicket { } hc.handshakeSession.setPskIdentity(nstm.ticket); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Consuming NewSessionTicket\n" + nstm); } } diff --git a/src/java.base/share/classes/sun/security/ssl/OutputRecord.java b/src/java.base/share/classes/sun/security/ssl/OutputRecord.java index f2c30b3ff72..416d5d1b5ef 100644 --- a/src/java.base/share/classes/sun/security/ssl/OutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/OutputRecord.java @@ -188,7 +188,7 @@ abstract class OutputRecord recordLock.lock(); try { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "change_cipher_spec message"); } @@ -222,7 +222,7 @@ abstract class OutputRecord recordLock.lock(); try { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "key_update handshake message"); } diff --git a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java index 819fdd589cb..b99c0175838 100644 --- a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java @@ -341,7 +341,7 @@ final class PreSharedKeyExtension { ServerHandshakeContext shc = (ServerHandshakeContext)context; // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(SSLExtension.CH_PRE_SHARED_KEY)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable pre_shared_key extension"); } @@ -393,7 +393,7 @@ final class PreSharedKeyExtension { } } if (b == null || s == null) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Stateless session ticket invalid"); @@ -402,7 +402,7 @@ final class PreSharedKeyExtension { } if (s != null && canRejoin(clientHello, shc, s)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Resuming session: ", s); } @@ -435,7 +435,7 @@ final class PreSharedKeyExtension { // Check protocol version if (result && s.getProtocolVersion() != shc.negotiatedProtocol) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest("Can't resume, incorrect protocol version"); @@ -449,7 +449,7 @@ final class PreSharedKeyExtension { try { s.getPeerPrincipal(); } catch (SSLPeerUnverifiedException e) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, " + @@ -466,7 +466,7 @@ final class PreSharedKeyExtension { if (result && !shc.localSupportedCertSignAlgs.containsAll(sessionSigAlgs)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Can't resume. Session uses different " + "signature algorithms"); } @@ -480,7 +480,7 @@ final class PreSharedKeyExtension { if (result && identityAlg != null) { String sessionIdentityAlg = s.getIdentificationProtocol(); if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest("Can't resume, endpoint id" + @@ -494,7 +494,7 @@ final class PreSharedKeyExtension { // Ensure cipher suite can be negotiated if (result && (!shc.isNegotiable(s.getSuite()) || !clientHello.cipherSuites.contains(s.getSuite()))) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Can't resume, unavailable session cipher suite"); @@ -653,7 +653,7 @@ final class PreSharedKeyExtension { // The producing happens in client side only. ClientHandshakeContext chc = (ClientHandshakeContext)context; if (!chc.isResumption || chc.resumingSession == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("No session to resume."); } return null; @@ -663,7 +663,7 @@ final class PreSharedKeyExtension { Collection sessionSigAlgs = chc.resumingSession.getLocalSupportedSignatureSchemes(); if (!chc.localSupportedCertSignAlgs.containsAll(sessionSigAlgs)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Existing session uses different " + "signature algorithms"); } @@ -673,7 +673,7 @@ final class PreSharedKeyExtension { // The session must have a pre-shared key SecretKey psk = chc.resumingSession.getPreSharedKey(); if (psk == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Existing session has no PSK."); } return null; @@ -687,7 +687,7 @@ final class PreSharedKeyExtension { } if (chc.pskIdentity == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "PSK has no identity, or identity was already used"); } @@ -699,7 +699,7 @@ final class PreSharedKeyExtension { chc.sslContext.engineGetClientSessionContext(); sessionCache.remove(chc.resumingSession.getSessionId(), true); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Found resumable session. Preparing PSK message."); SSLLogger.fine( @@ -836,7 +836,7 @@ final class PreSharedKeyExtension { public void absent(ConnectionContext context, HandshakeMessage message) throws IOException { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Handling pre_shared_key absence."); } @@ -901,7 +901,7 @@ final class PreSharedKeyExtension { } SHPreSharedKeySpec shPsk = new SHPreSharedKeySpec(chc, buffer); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Received pre_shared_key extension: ", shPsk); } @@ -911,7 +911,7 @@ final class PreSharedKeyExtension { "Selected identity index is not in correct range."); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Resuming session: ", chc.resumingSession); } @@ -925,7 +925,7 @@ final class PreSharedKeyExtension { HandshakeMessage message) throws IOException { ClientHandshakeContext chc = (ClientHandshakeContext)context; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Handling pre_shared_key absence."); } diff --git a/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java b/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java index e510fe92b0e..c826d9c89e3 100644 --- a/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java +++ b/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java @@ -246,7 +246,7 @@ final class PredefinedDHParameterSpecs { Matcher spacesMatcher = spacesPattern.matcher(property); property = spacesMatcher.replaceAll(""); - if (SSLLogger.isOn && SSLLogger.isOn("sslctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("sslctx")) { SSLLogger.fine( "The Security Property " + PROPERTY_NAME + ": " + property); @@ -262,7 +262,7 @@ final class PredefinedDHParameterSpecs { String primeModulus = paramsFinder.group(1); BigInteger p = new BigInteger(primeModulus, 16); if (!p.isProbablePrime(PRIME_CERTAINTY)) { - if (SSLLogger.isOn && SSLLogger.isOn("sslctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("sslctx")) { SSLLogger.fine( "Prime modulus p in Security Property, " + PROPERTY_NAME + ", is not a prime: " + @@ -279,7 +279,7 @@ final class PredefinedDHParameterSpecs { DHParameterSpec spec = new DHParameterSpec(p, g); defaultParams.put(primeLen, spec); } - } else if (SSLLogger.isOn && SSLLogger.isOn("sslctx")) { + } else if (SSLLogger.isOn() && SSLLogger.isOn("sslctx")) { SSLLogger.fine("Invalid Security Property, " + PROPERTY_NAME + ", definition"); } diff --git a/src/java.base/share/classes/sun/security/ssl/PskKeyExchangeModesExtension.java b/src/java.base/share/classes/sun/security/ssl/PskKeyExchangeModesExtension.java index 07707c5163a..a4f343ccb06 100644 --- a/src/java.base/share/classes/sun/security/ssl/PskKeyExchangeModesExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/PskKeyExchangeModesExtension.java @@ -184,7 +184,7 @@ final class PskKeyExchangeModesExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable( SSLExtension.PSK_KEY_EXCHANGE_MODES)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable psk_key_exchange_modes extension"); } @@ -216,7 +216,7 @@ final class PskKeyExchangeModesExtension { if (!spec.contains(PskKeyExchangeMode.PSK_DHE_KE)) { shc.isResumption = false; shc.resumingSession = null; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "abort session resumption, " + "no supported psk_dhe_ke PSK key exchange mode"); @@ -247,7 +247,7 @@ final class PskKeyExchangeModesExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable( SSLExtension.PSK_KEY_EXCHANGE_MODES)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Ignore unavailable psk_key_exchange_modes extension"); } @@ -287,7 +287,7 @@ final class PskKeyExchangeModesExtension { if (shc.isResumption) { // resumingSession may not be set shc.isResumption = false; shc.resumingSession = null; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "abort session resumption, " + "no supported psk_dhe_ke PSK key exchange mode"); diff --git a/src/java.base/share/classes/sun/security/ssl/QuicEngineOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/QuicEngineOutputRecord.java index 893eb282116..7e307ba9d27 100644 --- a/src/java.base/share/classes/sun/security/ssl/QuicEngineOutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/QuicEngineOutputRecord.java @@ -75,14 +75,14 @@ final class QuicEngineOutputRecord extends OutputRecord implements SSLRecord { recordLock.lock(); try { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "alert message: " + Alert.nameOf(description)); } return; } if (level == Alert.Level.WARNING.level) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("Suppressing warning-level " + "alert message: " + Alert.nameOf(description)); } @@ -90,7 +90,7 @@ final class QuicEngineOutputRecord extends OutputRecord implements SSLRecord { } if (alert != null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("Suppressing subsequent alert: " + description + ", original: " + alert.id); } @@ -109,7 +109,7 @@ final class QuicEngineOutputRecord extends OutputRecord implements SSLRecord { recordLock.lock(); try { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "handshake message", ByteBuffer.wrap(source, offset, length)); diff --git a/src/java.base/share/classes/sun/security/ssl/QuicKeyManager.java b/src/java.base/share/classes/sun/security/ssl/QuicKeyManager.java index fb9077af022..4613dcf96ff 100644 --- a/src/java.base/share/classes/sun/security/ssl/QuicKeyManager.java +++ b/src/java.base/share/classes/sun/security/ssl/QuicKeyManager.java @@ -244,7 +244,7 @@ sealed abstract class QuicKeyManager if (toDiscard == null) { return; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("discarding keys (keyphase=" + toDiscard.writeCipher.getKeyPhase() + ") of " + this.keySpace + " key space"); @@ -389,7 +389,7 @@ sealed abstract class QuicKeyManager if (toDiscard == null) { return; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("discarding keys (keyphase=" + toDiscard.writeCipher.getKeyPhase() + ") of " + this.keySpace + " key space"); @@ -570,7 +570,7 @@ sealed abstract class QuicKeyManager if (series == null) { return; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("discarding key (series) of " + this.keySpace + " key space"); } @@ -611,7 +611,7 @@ sealed abstract class QuicKeyManager if (series.canUseOldDecryptKey(packetNumber)) { final QuicReadCipher oldReadCipher = series.old; assert oldReadCipher != null : "old key is unexpectedly null"; - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("using old read key to decrypt packet: " + packetNumber + ", with incoming key phase: " + keyPhase + ", current key phase: " + @@ -633,7 +633,7 @@ sealed abstract class QuicKeyManager // KEY_UPDATE_ERROR. This indicates that a peer has // received and acknowledged a packet that initiates a key // update, but has not updated keys in response. - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("peer used incorrect key, was" + " expected to use updated key of" + " key phase: " + currentKeyPhase + @@ -646,7 +646,7 @@ sealed abstract class QuicKeyManager } return; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("detected ONE_RTT key update, current key " + "phase: " + currentKeyPhase + ", incoming key phase: " + keyPhase @@ -717,7 +717,7 @@ sealed abstract class QuicKeyManager } final long numEncrypted = cipher.getNumEncrypted(); if (numEncrypted >= 0.8 * confidentialityLimit) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("about to reach confidentiality limit, " + "attempting to initiate a 1-RTT key update," + " packet number: " + @@ -732,7 +732,7 @@ sealed abstract class QuicKeyManager : "key phase of updated key unexpectedly matches " + "the key phase " + cipher.getKeyPhase() + " of current keys"; - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest( "1-RTT key update initiated, new key phase: " + newKeyPhase); @@ -755,7 +755,7 @@ sealed abstract class QuicKeyManager // current key phase. This ensures that keys are // available to both peers before // another key update can be initiated. - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest( "skipping key update initiation because peer " + "hasn't yet sent us a packet encrypted with " + @@ -803,7 +803,7 @@ sealed abstract class QuicKeyManager // (we avoid timing attacks by not generating // keys during decryption, our key generation // only happens during encryption) - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("next keys unavailable," + " won't decrypt a packet which appears to be" + " a key update"); @@ -815,7 +815,7 @@ sealed abstract class QuicKeyManager // use the next keys to attempt decrypting currentKeySeries.next.readCipher.decryptPacket(packetNumber, packet, headerLength, output); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest( "decrypted using next keys for peer-initiated" + " key update; will now switch to new key phase: " + @@ -1025,14 +1025,14 @@ sealed abstract class QuicKeyManager // update the key series this.keySeries = newSeries; if (oldReadCipher != null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest( "discarding old read key of key phase: " + oldReadCipher.getKeyPhase()); } oldReadCipher.discard(false); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("discarding write key of key phase: " + writeCipherToDiscard.getKeyPhase()); } 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 6765f554fcc..18790a58c11 100644 --- a/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java @@ -560,7 +560,7 @@ public final class QuicTLSEngineImpl implements QuicTLSEngine, SSLTransport { // incoming crypto buffer is null. Validate message type, // check if size is available byte messageType = payload.get(payload.position()); - if (SSLLogger.isOn) { + if (SSLLogger.isOn()) { SSLLogger.fine("Received message of type 0x" + Integer.toHexString(messageType & 0xFF)); } @@ -835,7 +835,7 @@ public final class QuicTLSEngineImpl implements QuicTLSEngine, SSLTransport { final boolean confirmed = HANDSHAKE_STATE_HANDLE.compareAndSet(this, NEED_SEND_HANDSHAKE_DONE, HANDSHAKE_CONFIRMED); if (confirmed) { - if (SSLLogger.isOn) { + if (SSLLogger.isOn()) { SSLLogger.fine("QuicTLSEngine (server) marked handshake " + "state as HANDSHAKE_CONFIRMED"); } @@ -853,7 +853,7 @@ public final class QuicTLSEngineImpl implements QuicTLSEngine, SSLTransport { final boolean confirmed = HANDSHAKE_STATE_HANDLE.compareAndSet(this, NEED_RECV_HANDSHAKE_DONE, HANDSHAKE_CONFIRMED); if (confirmed) { - if (SSLLogger.isOn) { + if (SSLLogger.isOn()) { SSLLogger.fine( "QuicTLSEngine (client) received HANDSHAKE_DONE," + " marking state as HANDSHAKE_DONE"); diff --git a/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java index 701ba35174e..ec91cb4509a 100644 --- a/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java @@ -190,7 +190,7 @@ final class RSAClientKeyExchange { throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, "Cannot generate RSA premaster secret", gse); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced RSA ClientKeyExchange handshake message", ckem); } @@ -270,7 +270,7 @@ final class RSAClientKeyExchange { RSAClientKeyExchangeMessage ckem = new RSAClientKeyExchangeMessage(shc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming RSA ClientKeyExchange handshake message", ckem); } diff --git a/src/java.base/share/classes/sun/security/ssl/RSAKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/RSAKeyExchange.java index 311ac97e744..d176d7311d0 100644 --- a/src/java.base/share/classes/sun/security/ssl/RSAKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/RSAKeyExchange.java @@ -35,7 +35,6 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.interfaces.RSAPublicKey; -import java.security.spec.AlgorithmParameterSpec; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; @@ -150,7 +149,7 @@ final class RSAKeyExchange { needFailover = !KeyUtil.isOracleJCEProvider( cipher.getProvider().getName()); } catch (InvalidKeyException | UnsupportedOperationException iue) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("The Cipher provider " + safeProviderName(cipher) + " caused exception: " + iue.getMessage()); @@ -197,7 +196,7 @@ final class RSAKeyExchange { try { return cipher.getProvider().toString(); } catch (Exception e) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Retrieving The Cipher provider name" + " caused exception ", e); } @@ -205,7 +204,7 @@ final class RSAKeyExchange { try { return cipher.toString() + " (provider name not available)"; } catch (Exception e) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Retrieving The Cipher name" + " caused exception ", e); } @@ -220,7 +219,7 @@ final class RSAKeyExchange { int clientVersion, int serverVersion, byte[] encodedSecret, SecureRandom generator) throws GeneralSecurityException { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Generating a premaster secret"); } @@ -235,7 +234,7 @@ final class RSAKeyExchange { } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException iae) { // unlikely to happen, otherwise, must be a provider exception - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("RSA premaster secret generation error", iae); } diff --git a/src/java.base/share/classes/sun/security/ssl/RSAServerKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/RSAServerKeyExchange.java index 8633b9458ce..43f2ef95ba8 100644 --- a/src/java.base/share/classes/sun/security/ssl/RSAServerKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/RSAServerKeyExchange.java @@ -264,7 +264,7 @@ final class RSAServerKeyExchange { RSAServerKeyExchangeMessage skem = new RSAServerKeyExchangeMessage( shc, x509Possession, rsaPossession); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced RSA ServerKeyExchange handshake message", skem); } @@ -296,7 +296,7 @@ final class RSAServerKeyExchange { RSAServerKeyExchangeMessage skem = new RSAServerKeyExchangeMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming RSA ServerKeyExchange handshake message", skem); } diff --git a/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java b/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java index e1348badd30..90b9e999925 100644 --- a/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java @@ -138,7 +138,7 @@ final class RenegoInfoExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(CH_RENEGOTIATION_INFO)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable renegotiation_info extension"); } @@ -182,7 +182,7 @@ final class RenegoInfoExtension { return extData; } else { // not secure renegotiation if (HandshakeContext.allowUnsafeRenegotiation) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("Using insecure renegotiation"); } @@ -216,7 +216,7 @@ final class RenegoInfoExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(CH_RENEGOTIATION_INFO)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Ignore unavailable extension: " + CH_RENEGOTIATION_INFO.name); } @@ -280,7 +280,7 @@ final class RenegoInfoExtension { for (int id : clientHello.cipherSuiteIds) { if (id == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV.id) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "Safe renegotiation, using the SCSV signaling"); } @@ -294,7 +294,7 @@ final class RenegoInfoExtension { "Failed to negotiate the use of secure renegotiation"); } // otherwise, allow legacy hello message - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("Warning: No renegotiation " + "indication in ClientHello, allow legacy ClientHello"); } @@ -306,13 +306,13 @@ final class RenegoInfoExtension { "Inconsistent secure renegotiation indication"); } else { // renegotiation, not secure if (HandshakeContext.allowUnsafeRenegotiation) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("Using insecure renegotiation"); } } else { // Unsafe renegotiation should have been aborted in // earlier processes. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Terminate insecure renegotiation"); } throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, @@ -345,7 +345,7 @@ final class RenegoInfoExtension { if (requestedSpec == null && !shc.conContext.secureRenegotiation) { // Ignore, no renegotiation_info extension or SCSV signaling // requested. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "Ignore unavailable renegotiation_info extension"); } @@ -354,7 +354,7 @@ final class RenegoInfoExtension { if (!shc.conContext.secureRenegotiation) { // Ignore, no secure renegotiation is negotiated. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "No secure renegotiation has been negotiated"); } @@ -515,7 +515,7 @@ final class RenegoInfoExtension { "Failed to negotiate the use of secure renegotiation"); } // otherwise, allow legacy hello message - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("Warning: No renegotiation " + "indication in ServerHello, allow legacy ServerHello"); } @@ -527,13 +527,13 @@ final class RenegoInfoExtension { "Inconsistent secure renegotiation indication"); } else { // renegotiation, not secure if (HandshakeContext.allowUnsafeRenegotiation) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("Using insecure renegotiation"); } } else { // Unsafe renegotiation should have been aborted in // earlier processes. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Terminate insecure renegotiation"); } throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, diff --git a/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java index 1d5a4c4e73d..594766ea0fd 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java @@ -454,7 +454,7 @@ final class SSLAlgorithmConstraints implements AlgorithmConstraints { .equalsIgnoreCase(paramDigestAlg)); } catch (InvalidParameterSpecException e) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("Invalid AlgorithmParameters: " + parameters + "; Error: " + e.getMessage()); } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java index 4a52a2ea583..5dfa5be3420 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java @@ -392,7 +392,7 @@ enum SSLCipher { if (values[1].contains(tag[0])) { index = 0; } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("jdk.tls.keyLimits: Unknown action: " + entry); } @@ -413,13 +413,13 @@ enum SSLCipher { "Length exceeded limits"); } } catch (NumberFormatException e) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("jdk.tls.keyLimits: " + e.getMessage() + ": " + entry); } continue; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("jdk.tls.keyLimits: entry = " + entry + ". " + values[0] + ":" + tag[index] + " = " + size); } @@ -468,7 +468,7 @@ enum SSLCipher { Cipher.getInstance(transformation); return true; } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("Transformation " + transformation + " is" + " not available."); } @@ -860,7 +860,7 @@ enum SSLCipher { "JCE provider " + cipher.getProvider().getName(), sbe); } pt.position(pos); - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Plaintext after DECRYPTION", pt.duplicate()); } @@ -930,7 +930,7 @@ enum SSLCipher { authenticator.increaseSequenceNumber(); } - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.finest( "Padded plaintext before ENCRYPTION", bb.duplicate()); } @@ -1050,7 +1050,7 @@ enum SSLCipher { "JCE provider " + cipher.getProvider().getName(), sbe); } - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Padded plaintext after DECRYPTION", pt.duplicate().position(pos)); @@ -1182,7 +1182,7 @@ enum SSLCipher { int len = addPadding(bb, blockSize); bb.position(pos); - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Padded plaintext before ENCRYPTION", bb.duplicate()); @@ -1326,7 +1326,7 @@ enum SSLCipher { "JCE provider " + cipher.getProvider().getName(), sbe); } - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine("Padded plaintext after DECRYPTION", pt.duplicate().position(pos)); } @@ -1478,7 +1478,7 @@ enum SSLCipher { int len = addPadding(bb, blockSize); bb.position(pos); - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Padded plaintext before ENCRYPTION", bb.duplicate()); @@ -1650,7 +1650,7 @@ enum SSLCipher { pt.position(pos); pt.limit(pos + len); - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Plaintext after DECRYPTION", pt.duplicate()); } @@ -1737,7 +1737,7 @@ enum SSLCipher { // DON'T encrypt the nonce for AEAD mode. int len, pos = bb.position(); - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Plaintext before ENCRYPTION", bb.duplicate()); @@ -1823,7 +1823,7 @@ enum SSLCipher { keyLimitCountdown = cipherLimits.getOrDefault( algorithm.toUpperCase(Locale.ENGLISH) + ":" + tag[0], 0L); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("KeyLimit read side: algorithm = " + algorithm + ":" + tag[0] + "\ncountdown value = " + keyLimitCountdown); @@ -1932,7 +1932,7 @@ enum SSLCipher { contentType = pt.get(i); pt.limit(i); - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Plaintext after DECRYPTION", pt.duplicate()); } @@ -1984,7 +1984,7 @@ enum SSLCipher { keyLimitCountdown = cipherLimits.getOrDefault( algorithm.toUpperCase(Locale.ENGLISH) + ":" + tag[0], 0L); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("KeyLimit write side: algorithm = " + algorithm + ":" + tag[0] + "\ncountdown value = " + keyLimitCountdown); @@ -2026,7 +2026,7 @@ enum SSLCipher { cipher.updateAAD(aad); int len, pos = bb.position(); - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Plaintext before ENCRYPTION", bb.duplicate()); @@ -2182,7 +2182,7 @@ enum SSLCipher { pt.position(pos); pt.limit(pos + len); - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Plaintext after DECRYPTION", pt.duplicate()); } @@ -2231,7 +2231,7 @@ enum SSLCipher { keyLimitCountdown = cipherLimits.getOrDefault( algorithm.toUpperCase(Locale.ENGLISH) + ":" + tag[0], 0L); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("algorithm = " + algorithm + ":" + tag[0] + "\ncountdown value = " + keyLimitCountdown); @@ -2273,7 +2273,7 @@ enum SSLCipher { // DON'T encrypt the nonce for AEAD mode. int pos = bb.position(); - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Plaintext before ENCRYPTION", bb.duplicate()); @@ -2450,7 +2450,7 @@ enum SSLCipher { contentType = pt.get(i); pt.limit(i); - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Plaintext after DECRYPTION", pt.duplicate()); } @@ -2499,7 +2499,7 @@ enum SSLCipher { keyLimitCountdown = cipherLimits.getOrDefault( algorithm.toUpperCase(Locale.ENGLISH) + ":" + tag[0], 0L); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("algorithm = " + algorithm + ":" + tag[0] + "\ncountdown value = " + keyLimitCountdown); @@ -2541,7 +2541,7 @@ enum SSLCipher { cipher.updateAAD(aad); int pos = bb.position(); - if (SSLLogger.isOn && SSLLogger.isOn("plaintext")) { + if (SSLLogger.isOn() && SSLLogger.isOn("plaintext")) { SSLLogger.fine( "Plaintext before ENCRYPTION", bb.duplicate()); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java index 6d1834ad2b7..ace60e41af9 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java @@ -204,7 +204,7 @@ final class SSLConfiguration implements Cloneable { if (nstServerCount == null || nstServerCount < 0 || nstServerCount > 10) { serverNewSessionTicketCount = SERVER_NST_DEFAULT; - if (nstServerCount != null && SSLLogger.isOn && + if (nstServerCount != null && SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "jdk.tls.server.newSessionTicketCount defaults to " + @@ -213,7 +213,7 @@ final class SSLConfiguration implements Cloneable { } } else { serverNewSessionTicketCount = nstServerCount; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "jdk.tls.server.newSessionTicketCount set to " + serverNewSessionTicketCount); @@ -586,7 +586,7 @@ final class SSLConfiguration implements Cloneable { String property = System.getProperty(propertyName); // this method is called from class initializer; logging here // will occasionally pin threads and deadlock if called from a virtual thread - if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx") + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx") && !Thread.currentThread().isVirtual()) { SSLLogger.fine( "System property " + propertyName + " is set to '" + @@ -615,7 +615,7 @@ final class SSLConfiguration implements Cloneable { if (scheme != null && scheme.isAvailable) { signatureSchemes.add(schemeName); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx") + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx") && !Thread.currentThread().isVirtual()) { SSLLogger.fine( "The current installed providers do not " + 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 d50a9a10b76..be324eb0949 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java @@ -104,11 +104,11 @@ public abstract class SSLContextImpl extends SSLContextSpi { * first connection to time out and fail. Make sure it is * primed and ready by getting some initial output from it. */ - if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx")) { SSLLogger.finest("trigger seeding of SecureRandom"); } secureRandom.nextInt(); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx")) { SSLLogger.finest("done seeding of SecureRandom"); } @@ -143,7 +143,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { return (X509ExtendedKeyManager)km; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx")) { SSLLogger.warning( "X509KeyManager passed to SSLContext.init(): need an " + "X509ExtendedKeyManager for SSLEngine use"); @@ -246,7 +246,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { contextLock.lock(); try { if (statusResponseManager == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx")) { SSLLogger.finest( "Initializing StatusResponseManager"); } @@ -383,7 +383,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { suite.name, null)) { suites.add(suite); isSupported = true; - } else if (SSLLogger.isOn && + } else if (SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx,verbose")) { SSLLogger.fine( "Ignore disabled cipher suite: " + suite.name); @@ -392,7 +392,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { break; } - if (!isSupported && SSLLogger.isOn && + if (!isSupported && SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx,verbose")) { SSLLogger.finest( "Ignore unsupported cipher suite: " + suite); @@ -410,7 +410,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { String propertyName) { String property = System.getProperty(propertyName); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx")) { SSLLogger.fine( "System property " + propertyName + " is set to '" + property + "'"); @@ -437,7 +437,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { try { suite = CipherSuite.nameOf(cipherSuiteNames[i]); } catch (IllegalArgumentException iae) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx")) { SSLLogger.fine( "Unknown or unsupported cipher suite name: " + cipherSuiteNames[i]); @@ -449,7 +449,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { if (suite != null && suite.isAvailable()) { cipherSuites.add(suite); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx")) { SSLLogger.fine( "The current installed providers do not " + "support cipher suite: " + cipherSuiteNames[i]); @@ -907,7 +907,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { tmMediator = getTrustManagers(); } catch (Exception e) { reserved = e; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,defaultctx")) { SSLLogger.warning( "Failed to load default trust managers", e); } @@ -919,7 +919,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { kmMediator = getKeyManagers(); } catch (Exception e) { reserved = e; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,defaultctx")) { SSLLogger.warning( "Failed to load default key managers", e); } @@ -977,7 +977,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { String defaultKeyStore = props.get("keyStore"); String defaultKeyStoreType = props.get("keyStoreType"); String defaultKeyStoreProvider = props.get("keyStoreProvider"); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,defaultctx")) { SSLLogger.fine("keyStore is : " + defaultKeyStore); SSLLogger.fine("keyStore type is : " + defaultKeyStoreType); @@ -1007,7 +1007,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { // Try to initialize key store. if ((defaultKeyStoreType.length()) != 0) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,defaultctx")) { SSLLogger.finest("init keystore"); } if (defaultKeyStoreProvider.isEmpty()) { @@ -1030,7 +1030,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { /* * Try to initialize key manager. */ - if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,defaultctx")) { SSLLogger.fine("init keymanager of type " + KeyManagerFactory.getDefaultAlgorithm()); } @@ -1068,7 +1068,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { // exception object, which may be not garbage collection // friendly as 'reservedException' is a static filed. reserved = new KeyManagementException(e.getMessage()); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,defaultctx")) { SSLLogger.warning( "Failed to load default SSLContext", e); } @@ -1097,7 +1097,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { super.engineInit(DefaultManagersHolder.keyManagers, DefaultManagersHolder.trustManagers, null); } catch (Exception e) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,defaultctx")) { SSLLogger.fine("default context init failed: ", e); } throw e; diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java index 4b19f5a9d7b..5e23e6ee37b 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -330,7 +330,7 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { // application data may be discarded accordingly. As could // be an issue for some applications. This impact can be // mitigated by sending the last flight twice. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,verbose")) { SSLLogger.finest("retransmit the last flight messages"); } @@ -397,7 +397,7 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { if ((conContext.handshakeContext == null) && !conContext.isOutboundClosed() && !conContext.isBroken) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("trigger key update"); } beginHandshake(); @@ -419,7 +419,7 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { !conContext.isOutboundClosed() && !conContext.isInboundClosed() && !conContext.isBroken) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("trigger NST"); } conContext.conSession.updateNST = false; @@ -612,7 +612,7 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { } catch (SSLException ssle) { // Need to discard invalid records for DTLS protocols. if (sslContext.isDTLS()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,verbose")) { SSLLogger.finest("Discard invalid DTLS records", ssle); } @@ -780,7 +780,7 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { return; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("Closing inbound of SSLEngine"); } @@ -819,7 +819,7 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { return; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("Closing outbound of SSLEngine"); } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java index 1bfbd9f51bf..6e08fc71664 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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 @@ -172,7 +172,7 @@ final class SSLEngineInputRecord extends InputRecord implements SSLRecord { return null; } - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw read", packet); } @@ -209,7 +209,7 @@ final class SSLEngineInputRecord extends InputRecord implements SSLRecord { byte minorVersion = packet.get(); // pos: 2 int contentLen = Record.getInt16(packet); // pos: 3, 4 - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "READ: " + ProtocolVersion.nameOf(majorVersion, minorVersion) + @@ -388,7 +388,7 @@ final class SSLEngineInputRecord extends InputRecord implements SSLRecord { * error message, one that's treated as fatal by * clients (Otherwise we'll hang.) */ - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "Requested to negotiate unsupported SSLv2!"); } @@ -410,7 +410,7 @@ final class SSLEngineInputRecord extends InputRecord implements SSLRecord { ByteBuffer converted = convertToClientHello(packet); - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine( "[Converted] ClientHello", converted); } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java index 4a689a84d5f..1c8751e66fe 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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 @@ -73,7 +73,7 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { @Override void encodeAlert(byte level, byte description) { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "alert message: " + Alert.nameOf(description)); } @@ -91,7 +91,7 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { void encodeHandshake(byte[] source, int offset, int length) { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "handshake message", ByteBuffer.wrap(source, offset, length)); @@ -138,7 +138,7 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { @Override void encodeChangeCipherSpec() { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "change_cipher_spec message"); } @@ -171,14 +171,14 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException { if (isClosed) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "application data or cached messages"); } return null; } else if (isCloseWaiting) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "application data"); } @@ -193,7 +193,7 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { ByteBuffer destination) throws IOException { if (writeCipher.authenticator.seqNumOverflow()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine( "sequence number extremely close to overflow " + "(2^64-1 packets). Closing connection."); @@ -275,7 +275,7 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { destination.limit(destination.position()); destination.position(dstContent); - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "WRITE: " + protocolVersion.name + " " + ContentType.APPLICATION_DATA.name + @@ -288,7 +288,7 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { dstPos, dstLim, headerSize, protocolVersion); - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { ByteBuffer temporary = destination.duplicate(); temporary.limit(temporary.position()); temporary.position(dstPos); @@ -317,7 +317,7 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { // // Please don't change the limit of the destination buffer. destination.put(SSLRecord.v2NoCipher); - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw write", SSLRecord.v2NoCipher); } @@ -331,7 +331,7 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { // deliver the SSLv2 format ClientHello message // // Please don't change the limit of the destination buffer. - if (SSLLogger.isOn) { + if (SSLLogger.isOn()) { if (SSLLogger.isOn("record")) { SSLLogger.fine(Thread.currentThread().getName() + ", WRITE: SSLv2 ClientHello message" + @@ -525,7 +525,7 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { dstBuf.limit(dstBuf.position()); dstBuf.position(dstContent); - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "WRITE: " + protocolVersion.name + " " + ContentType.nameOf(memo.contentType) + @@ -543,7 +543,7 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord { memo.encodeCipher.dispose(); } - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { ByteBuffer temporary = dstBuf.duplicate(); temporary.limit(temporary.position()); temporary.position(dstPos); 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 fb0490d70f1..47a0d0b0e44 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLExtension.java @@ -844,7 +844,7 @@ enum SSLExtension implements SSLStringizer { String property = System.getProperty(propertyName); // this method is called from class initializer; logging here // will occasionally pin threads and deadlock if called from a virtual thread - if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx") + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,sslctx") && !Thread.currentThread().isVirtual()) { SSLLogger.fine( "System property " + propertyName + " is set to '" + diff --git a/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java b/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java index 5ad93cfc836..66f6293302e 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLExtensions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -43,7 +43,7 @@ final class SSLExtensions { // Extension map for debug logging private final Map logMap = - SSLLogger.isOn ? new LinkedHashMap<>() : null; + SSLLogger.isOn() ? new LinkedHashMap<>() : null; SSLExtensions(HandshakeMessage handshakeMessage) { this.handshakeMessage = handshakeMessage; @@ -93,7 +93,7 @@ final class SSLExtensions { // However, the implementation of the limit is complicated // and inefficient, and may not worthy the maintenance. isSupported = false; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Received buggy supported_groups extension " + "in the ServerHello handshake message"); @@ -143,7 +143,7 @@ final class SSLExtensions { m.get(extData); logMap.put(extId, extData); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unknown or unsupported extension", toString(extId, extData)); @@ -171,7 +171,7 @@ final class SSLExtensions { for (SSLExtension extension : extensions) { if (context.negotiatedProtocol != null && !extension.isAvailable(context.negotiatedProtocol)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unsupported extension: " + extension.name); } @@ -181,7 +181,7 @@ final class SSLExtensions { if (!extMap.containsKey(extension)) { if (extension.onLoadAbsence != null) { extension.absentOnLoad(context, handshakeMessage); - } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + } else if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extension: " + extension.name); } @@ -190,7 +190,7 @@ final class SSLExtensions { if (extension.onLoadConsumer == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Ignore unsupported extension: " + extension.name); } @@ -200,7 +200,7 @@ final class SSLExtensions { ByteBuffer m = ByteBuffer.wrap(extMap.get(extension)); extension.consumeOnLoad(context, handshakeMessage, m); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Consumed extension: " + extension.name); } } @@ -215,7 +215,7 @@ final class SSLExtensions { if (!extMap.containsKey(extension)) { if (extension.onTradeAbsence != null) { extension.absentOnTrade(context, handshakeMessage); - } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + } else if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extension: " + extension.name); } @@ -223,7 +223,7 @@ final class SSLExtensions { } if (extension.onTradeConsumer == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Ignore impact of unsupported extension: " + extension.name); @@ -232,7 +232,7 @@ final class SSLExtensions { } extension.consumeOnTrade(context, handshakeMessage); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Populated with extension: " + extension.name); } } @@ -245,7 +245,7 @@ final class SSLExtensions { SSLExtension[] extensions) throws IOException { for (SSLExtension extension : extensions) { if (extMap.containsKey(extension)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore, duplicated extension: " + extension.name); @@ -254,7 +254,7 @@ final class SSLExtensions { } if (extension.networkProducer == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Ignore, no extension producer defined: " + extension.name); @@ -267,7 +267,7 @@ final class SSLExtensions { extMap.put(extension, encoded); encodedLength += encoded.length + 4; // extension_type (2) // extension_data length(2) - } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + } else if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { // The extension is not available in the context. SSLLogger.fine( "Ignore, context unavailable extension: " + @@ -284,7 +284,7 @@ final class SSLExtensions { SSLExtension[] extensions) throws IOException { for (SSLExtension extension : extensions) { if (extension.networkProducer == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Ignore, no extension producer defined: " + extension.name); @@ -305,7 +305,7 @@ final class SSLExtensions { encodedLength += encoded.length + 4; // extension_type (2) // extension_data length(2) - } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + } else if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { // The extension is not available in the context. SSLLogger.fine( "Ignore, context unavailable extension: " + diff --git a/src/java.base/share/classes/sun/security/ssl/SSLLogger.java b/src/java.base/share/classes/sun/security/ssl/SSLLogger.java index f55ab27d297..7fa6fbf91b5 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLLogger.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLLogger.java @@ -29,8 +29,6 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; -import java.lang.System.Logger; -import java.lang.System.Logger.Level; import java.nio.ByteBuffer; import java.security.cert.Certificate; import java.security.cert.Extension; @@ -41,6 +39,7 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.*; +import jdk.internal.vm.annotation.ForceInline; import sun.security.util.HexDumpEncoder; import sun.security.util.Debug; import sun.security.x509.*; @@ -58,10 +57,13 @@ import static sun.security.ssl.Utilities.LINE_SEP; * logging mechanisms. If the system property "javax.net.debug" is defined * and non-empty, a private debug logger implemented in this class is used. */ -public final class SSLLogger { +public final class SSLLogger implements System.Logger { private static final System.Logger logger; private static final String property; - public static final boolean isOn; + private static final boolean isOn; + + private final String loggerName; + private final boolean useCompactFormat; static { @@ -76,7 +78,7 @@ public final class SSLLogger { help(); } - logger = new SSLConsoleLogger("javax.net.ssl", p); + logger = new SSLLogger("javax.net.ssl", p); } isOn = true; } else { @@ -86,6 +88,105 @@ public final class SSLLogger { } } + private SSLLogger(String loggerName, String options) { + this.loggerName = loggerName; + options = options.toLowerCase(Locale.ENGLISH); + this.useCompactFormat = !options.contains("expand"); + } + + /** + * Return true if the "javax.net.debug" property contains the + * debug check points, or System.Logger is used. + */ + public static boolean isOn(String checkPoints) { + if (property == null) { // debugging is turned off + return false; + } else if (property.isEmpty()) { // use System.Logger + return true; + } // use provider logger + + String[] options = checkPoints.split(","); + for (String option : options) { + option = option.trim(); + if (!SSLLogger.hasOption(option)) { + return false; + } + } + + return true; + } + + @ForceInline + public static boolean isOn() { + return isOn; + } + + private static boolean hasOption(String option) { + option = option.toLowerCase(Locale.ENGLISH); + if (property.contains("all")) { + return true; + } else { + // remove first occurrence of "sslctx" since + // it interferes with search for "ssl" + String modified = property.replaceFirst("sslctx", ""); + if (modified.contains("ssl")) { + // don't enable data and plaintext options by default + if (!(option.equals("data") + || option.equals("packet") + || option.equals("plaintext"))) { + return true; + } + } + } + + return property.contains(option); + } + + public static void severe(String msg, Object... params) { + SSLLogger.log0(Level.ERROR, msg, params); + } + + public static void warning(String msg, Object... params) { + SSLLogger.log0(Level.WARNING, msg, params); + } + + public static void info(String msg, Object... params) { + SSLLogger.log0(Level.INFO, msg, params); + } + + public static void fine(String msg, Object... params) { + SSLLogger.log0(Level.DEBUG, msg, params); + } + + public static void finer(String msg, Object... params) { + SSLLogger.log0(Level.TRACE, msg, params); + } + + public static void finest(String msg, Object... params) { + SSLLogger.log0(Level.TRACE, msg, params); + } + + private static void log0(Level level, String msg, Object... params) { + if (logger != null && logger.isLoggable(level)) { + if (params == null || params.length == 0) { + logger.log(level, msg); + } else { + try { + String formatted = + SSLSimpleFormatter.formatParameters(params); + // use the customized log method for SSLLogger + if (logger instanceof SSLLogger) { + logger.log(level, msg, formatted); + } else { + logger.log(level, msg + ":" + LINE_SEP + formatted); + } + } catch (Exception exp) { + // ignore it, just for debugging. + } + } + } + } + private static void help() { System.err.println(); System.err.println("help print the help messages"); @@ -117,94 +218,6 @@ public final class SSLLogger { System.exit(0); } - /** - * Return true if the "javax.net.debug" property contains the - * debug check points, or System.Logger is used. - */ - public static boolean isOn(String checkPoints) { - if (property == null) { // debugging is turned off - return false; - } else if (property.isEmpty()) { // use System.Logger - return true; - } // use provider logger - - String[] options = checkPoints.split(","); - for (String option : options) { - option = option.trim(); - if (!SSLLogger.hasOption(option)) { - return false; - } - } - - return true; - } - - private static boolean hasOption(String option) { - option = option.toLowerCase(Locale.ENGLISH); - if (property.contains("all")) { - return true; - } else { - // remove first occurrence of "sslctx" since - // it interferes with search for "ssl" - String modified = property.replaceFirst("sslctx", ""); - if (modified.contains("ssl")) { - // don't enable data and plaintext options by default - if (!(option.equals("data") - || option.equals("packet") - || option.equals("plaintext"))) { - return true; - } - } - } - - return property.contains(option); - } - - public static void severe(String msg, Object... params) { - SSLLogger.log(Level.ERROR, msg, params); - } - - public static void warning(String msg, Object... params) { - SSLLogger.log(Level.WARNING, msg, params); - } - - public static void info(String msg, Object... params) { - SSLLogger.log(Level.INFO, msg, params); - } - - public static void fine(String msg, Object... params) { - SSLLogger.log(Level.DEBUG, msg, params); - } - - public static void finer(String msg, Object... params) { - SSLLogger.log(Level.TRACE, msg, params); - } - - public static void finest(String msg, Object... params) { - SSLLogger.log(Level.TRACE, msg, params); - } - - private static void log(Level level, String msg, Object... params) { - if (logger != null && logger.isLoggable(level)) { - if (params == null || params.length == 0) { - logger.log(level, msg); - } else { - try { - String formatted = - SSLSimpleFormatter.formatParameters(params); - // use the customized log method for SSLConsoleLogger - if (logger instanceof SSLConsoleLogger) { - logger.log(level, msg, formatted); - } else { - logger.log(level, msg + ":" + LINE_SEP + formatted); - } - } catch (Exception exp) { - // ignore it, just for debugging. - } - } - } - } - static String toString(Object... params) { try { return SSLSimpleFormatter.formatParameters(params); @@ -216,65 +229,55 @@ public final class SSLLogger { // Logs a warning message and always returns false. This method // can be used as an OR Predicate to add a log in a stream filter. public static boolean logWarning(String option, String s) { - if (SSLLogger.isOn && SSLLogger.isOn(option)) { + if (SSLLogger.isOn() && SSLLogger.isOn(option)) { SSLLogger.warning(s); } return false; } - private static class SSLConsoleLogger implements Logger { - private final String loggerName; - private final boolean useCompactFormat; + @Override + public String getName() { + return loggerName; + } - SSLConsoleLogger(String loggerName, String options) { - this.loggerName = loggerName; - options = options.toLowerCase(Locale.ENGLISH); - this.useCompactFormat = !options.contains("expand"); - } + @Override + public boolean isLoggable(Level level) { + return level != Level.OFF; + } - @Override - public String getName() { - return loggerName; - } - - @Override - public boolean isLoggable(Level level) { - return level != Level.OFF; - } - - @Override - public void log(Level level, - ResourceBundle rb, String message, Throwable thrwbl) { - if (isLoggable(level)) { - try { - String formatted = + @Override + public void log(Level level, + ResourceBundle rb, String message, Throwable thrwbl) { + if (isLoggable(level)) { + try { + String formatted = SSLSimpleFormatter.format(this, level, message, thrwbl); - System.err.write(formatted.getBytes(UTF_8)); - } catch (Exception exp) { - // ignore it, just for debugging. - } + System.err.write(formatted.getBytes(UTF_8)); + } catch (Exception exp) { + // ignore it, just for debugging. } } + } - @Override - public void log(Level level, - ResourceBundle rb, String message, Object... params) { - if (isLoggable(level)) { - try { - String formatted = + @Override + public void log(Level level, + ResourceBundle rb, String message, Object... params) { + if (isLoggable(level)) { + try { + String formatted = SSLSimpleFormatter.format(this, level, message, params); - System.err.write(formatted.getBytes(UTF_8)); - } catch (Exception exp) { - // ignore it, just for debugging. - } + System.err.write(formatted.getBytes(UTF_8)); + } catch (Exception exp) { + // ignore it, just for debugging. } } } private static class SSLSimpleFormatter { private static final String PATTERN = "yyyy-MM-dd kk:mm:ss.SSS z"; - private static final DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern(PATTERN, Locale.ENGLISH) - .withZone(ZoneId.systemDefault()); + private static final DateTimeFormatter dateTimeFormat = + DateTimeFormatter.ofPattern(PATTERN, Locale.ENGLISH) + .withZone(ZoneId.systemDefault()); private static final MessageFormat basicCertFormat = new MessageFormat( """ @@ -290,68 +293,68 @@ public final class SSLLogger { Locale.ENGLISH); private static final MessageFormat extendedCertFormat = - new MessageFormat( - """ - "version" : "v{0}", - "serial number" : "{1}", - "signature algorithm": "{2}", - "issuer" : "{3}", - "not before" : "{4}", - "not after" : "{5}", - "subject" : "{6}", - "subject public key" : "{7}", - "extensions" : [ - {8} - ] - """, - Locale.ENGLISH); + new MessageFormat( + """ + "version" : "v{0}", + "serial number" : "{1}", + "signature algorithm": "{2}", + "issuer" : "{3}", + "not before" : "{4}", + "not after" : "{5}", + "subject" : "{6}", + "subject public key" : "{7}", + "extensions" : [ + {8} + ] + """, + Locale.ENGLISH); private static final MessageFormat messageFormatNoParas = - new MessageFormat( - """ - '{' - "logger" : "{0}", - "level" : "{1}", - "thread id" : "{2}", - "thread name" : "{3}", - "time" : "{4}", - "caller" : "{5}", - "message" : "{6}" - '}' - """, - Locale.ENGLISH); + new MessageFormat( + """ + '{' + "logger" : "{0}", + "level" : "{1}", + "thread id" : "{2}", + "thread name" : "{3}", + "time" : "{4}", + "caller" : "{5}", + "message" : "{6}" + '}' + """, + Locale.ENGLISH); private static final MessageFormat messageCompactFormatNoParas = - new MessageFormat( - "{0}|{1}|{2}|{3}|{4}|{5}|{6}" + LINE_SEP, - Locale.ENGLISH); + new MessageFormat( + "{0}|{1}|{2}|{3}|{4}|{5}|{6}" + LINE_SEP, + Locale.ENGLISH); private static final MessageFormat messageFormatWithParas = - new MessageFormat( - """ - '{' - "logger" : "{0}", - "level" : "{1}", - "thread id" : "{2}", - "thread name" : "{3}", - "time" : "{4}", - "caller" : "{5}", - "message" : "{6}", - "specifics" : [ - {7} - ] - '}' - """, - Locale.ENGLISH); + new MessageFormat( + """ + '{' + "logger" : "{0}", + "level" : "{1}", + "thread id" : "{2}", + "thread name" : "{3}", + "time" : "{4}", + "caller" : "{5}", + "message" : "{6}", + "specifics" : [ + {7} + ] + '}' + """, + Locale.ENGLISH); private static final MessageFormat messageCompactFormatWithParas = - new MessageFormat( - """ - {0}|{1}|{2}|{3}|{4}|{5}|{6} ( - {7} - ) - """, - Locale.ENGLISH); + new MessageFormat( + """ + {0}|{1}|{2}|{3}|{4}|{5}|{6} ( + {7} + ) + """, + Locale.ENGLISH); private static final MessageFormat keyObjectFormat = new MessageFormat( """ @@ -364,8 +367,8 @@ public final class SSLLogger { // log message // log message // ... - private static String format(SSLConsoleLogger logger, Level level, - String message, Object ... parameters) { + private static String format(SSLLogger logger, Level level, + String message, Object... parameters) { if (parameters == null || parameters.length == 0) { Object[] messageFields = { @@ -394,9 +397,9 @@ public final class SSLLogger { formatCaller(), message, (logger.useCompactFormat ? - formatParameters(parameters) : - Utilities.indent(formatParameters(parameters))) - }; + formatParameters(parameters) : + Utilities.indent(formatParameters(parameters))) + }; if (logger.useCompactFormat) { return messageCompactFormatWithParas.format(messageFields); @@ -414,7 +417,7 @@ public final class SSLLogger { .findFirst().orElse("unknown caller")); } - private static String formatParameters(Object ... parameters) { + private static String formatParameters(Object... parameters) { StringBuilder builder = new StringBuilder(512); boolean isFirst = true; for (Object parameter : parameters) { @@ -425,21 +428,21 @@ public final class SSLLogger { } if (parameter instanceof Throwable) { - builder.append(formatThrowable((Throwable)parameter)); + builder.append(formatThrowable((Throwable) parameter)); } else if (parameter instanceof Certificate) { - builder.append(formatCertificate((Certificate)parameter)); + builder.append(formatCertificate((Certificate) parameter)); } else if (parameter instanceof ByteArrayInputStream) { builder.append(formatByteArrayInputStream( - (ByteArrayInputStream)parameter)); + (ByteArrayInputStream) parameter)); } else if (parameter instanceof ByteBuffer) { - builder.append(formatByteBuffer((ByteBuffer)parameter)); + builder.append(formatByteBuffer((ByteBuffer) parameter)); } else if (parameter instanceof byte[]) { builder.append(formatByteArrayInputStream( - new ByteArrayInputStream((byte[])parameter))); + new ByteArrayInputStream((byte[]) parameter))); } else if (parameter instanceof Map.Entry) { @SuppressWarnings("unchecked") Map.Entry mapParameter = - (Map.Entry)parameter; + (Map.Entry) parameter; builder.append(formatMapEntry(mapParameter)); } else { builder.append(formatObject(parameter)); @@ -462,7 +465,7 @@ public final class SSLLogger { Object[] fields = { "throwable", builder.toString() - }; + }; return keyObjectFormat.format(fields); } @@ -479,7 +482,7 @@ public final class SSLLogger { StringBuilder builder = new StringBuilder(512); try { X509CertImpl x509 = - X509CertImpl.toImpl((X509Certificate)certificate); + X509CertImpl.toImpl((X509Certificate) certificate); X509CertInfo certInfo = x509.getInfo(); CertificateExtensions certExts = certInfo.getExtensions(); if (certExts == null) { @@ -528,7 +531,7 @@ public final class SSLLogger { Object[] fields = { "certificate", builder.toString() - }; + }; return Utilities.indent(keyObjectFormat.format(fields)); } @@ -591,13 +594,13 @@ public final class SSLLogger { formatted = builder.toString(); } else if (value instanceof byte[]) { formatted = "\"" + key + "\": \"" + - Utilities.toHexString((byte[])value) + "\""; + Utilities.toHexString((byte[]) value) + "\""; } else if (value instanceof Byte) { formatted = "\"" + key + "\": \"" + - HexFormat.of().toHexDigits((byte)value) + "\""; + HexFormat.of().toHexDigits((byte) value) + "\""; } else { formatted = "\"" + key + "\": " + - "\"" + value.toString() + "\""; + "\"" + value.toString() + "\""; } return Utilities.indent(formatted); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLMasterKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/SSLMasterKeyDerivation.java index db5887c5e8e..4de29b7570a 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLMasterKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLMasterKeyDerivation.java @@ -29,7 +29,6 @@ import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.ProviderException; -import java.security.spec.AlgorithmParameterSpec; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import sun.security.internal.spec.TlsMasterSecretParameterSpec; @@ -152,7 +151,7 @@ enum SSLMasterKeyDerivation implements SSLKeyDerivationGenerator { // // For RSA premaster secrets, do not signal a protocol error // due to the Bleichenbacher attack. See comments further down. - if (SSLLogger.isOn && SSLLogger.isOn("handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("handshake")) { SSLLogger.fine("RSA master secret generation error.", iae); } throw new ProviderException(iae); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java index 4baa3304fee..f713f723ea0 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java @@ -339,7 +339,7 @@ final class SSLSessionContextImpl implements SSLSessionContext { if (t < 0 || t > NewSessionTicket.MAX_TICKET_LIFETIME) { timeout = DEFAULT_SESSION_TIMEOUT; - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("Invalid timeout given " + "jdk.tls.server.sessionTicketTimeout: " + t + ". Set to default value " + timeout); @@ -349,7 +349,7 @@ final class SSLSessionContextImpl implements SSLSessionContext { } } catch (NumberFormatException e) { setSessionTimeout(DEFAULT_SESSION_TIMEOUT); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("Invalid timeout for " + "jdk.tls.server.sessionTicketTimeout: " + s + ". Set to default value " + timeout); @@ -363,7 +363,7 @@ final class SSLSessionContextImpl implements SSLSessionContext { if (defaultCacheLimit >= 0) { return defaultCacheLimit; - } else if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + } else if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning( "invalid System Property javax.net.ssl.sessionCacheSize, " + "use the default session cache size (" + @@ -371,7 +371,7 @@ final class SSLSessionContextImpl implements SSLSessionContext { } } catch (Exception e) { // unlikely, log it for safe - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning( "the System Property javax.net.ssl.sessionCacheSize is " + "not available, use the default value (" + diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java index 1bf561c47e6..f3a4b964158 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java @@ -223,7 +223,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { this.identificationProtocol = hc.sslConfig.identificationProtocol; this.boundValues = new ConcurrentHashMap<>(); - if (SSLLogger.isOn && SSLLogger.isOn("session")) { + if (SSLLogger.isOn() && SSLLogger.isOn("session")) { SSLLogger.finest("Session initialized: " + this); } } @@ -256,7 +256,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { this.maximumPacketSize = baseSession.maximumPacketSize; this.boundValues = baseSession.boundValues; - if (SSLLogger.isOn && SSLLogger.isOn("session")) { + if (SSLLogger.isOn() && SSLLogger.isOn("session")) { SSLLogger.finest("Session initialized: " + this); } } @@ -455,7 +455,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { if (same) { this.localCerts = ((X509Possession) pos).popCerts; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,session")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,session")) { SSLLogger.fine("Restored " + len + " local certificates from session ticket" + " for algorithms " + Arrays.toString(certAlgs)); @@ -463,7 +463,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { } else { this.localCerts = null; this.invalidated = true; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,session")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,session")) { SSLLogger.warning("Local certificates can not be restored " + "from session ticket " + "for algorithms " + Arrays.toString(certAlgs)); @@ -482,7 +482,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { // If there is no getMasterSecret with TLS1.2 or under, do not resume. if (!protocolVersion.useTLS13PlusSpec() && getMasterSecret().getEncoded() == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest("No MasterSecret, cannot make stateless" + " ticket"); } @@ -490,7 +490,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { } if (boundValues != null && boundValues.size() > 0) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest("There are boundValues, cannot make" + " stateless ticket"); } @@ -862,7 +862,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { void setSuite(CipherSuite suite) { cipherSuite = suite; - if (SSLLogger.isOn && SSLLogger.isOn("session")) { + if (SSLLogger.isOn() && SSLLogger.isOn("session")) { SSLLogger.finest("Negotiating session: " + this); } } @@ -1132,7 +1132,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { return; } invalidated = true; - if (SSLLogger.isOn && SSLLogger.isOn("session")) { + if (SSLLogger.isOn() && SSLLogger.isOn("session")) { SSLLogger.finest("Invalidated session: " + this); } for (SSLSessionImpl child : childSessions) { 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 be95a09006f..ab01a9d85be 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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,7 @@ public final class SSLSocketImpl // start handshaking, if failed, the connection will be closed. ensureNegotiated(false); } catch (IOException ioe) { - if (SSLLogger.isOn && SSLLogger.isOn("handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("handshake")) { SSLLogger.severe("handshake failed", ioe); } @@ -573,7 +573,7 @@ public final class SSLSocketImpl return; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("duplex close of SSLSocket"); } @@ -591,7 +591,7 @@ public final class SSLSocketImpl } } catch (IOException ioe) { // ignore the exception - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("SSLSocket duplex close failed. Debug info only. Exception details:", ioe); } } finally { @@ -601,7 +601,7 @@ public final class SSLSocketImpl closeSocket(false); } catch (IOException ioe) { // ignore the exception - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("SSLSocket close failed. Debug info only. Exception details:", ioe); } } finally { @@ -696,7 +696,7 @@ public final class SSLSocketImpl "close_notify message cannot be sent."); } else { super.shutdownOutput(); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning( "SSLSocket output duplex close failed: " + "SO_LINGER timeout, " + @@ -717,7 +717,7 @@ public final class SSLSocketImpl // failed to send the close_notify message. // conContext.conSession.invalidate(); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning( "Invalidate the session: SO_LINGER timeout, " + "close_notify message cannot be sent."); @@ -832,7 +832,7 @@ public final class SSLSocketImpl return; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("close inbound of SSLSocket"); } @@ -868,7 +868,7 @@ public final class SSLSocketImpl return; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("close outbound of SSLSocket"); } conContext.closeOutbound(); @@ -1027,7 +1027,7 @@ public final class SSLSocketImpl // filed is checked here, in case the closing process is // still in progress. if (hasDepleted) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("The input stream has been depleted"); } @@ -1048,7 +1048,7 @@ public final class SSLSocketImpl // Double check if the input stream has been depleted. if (hasDepleted) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("The input stream is closing"); } @@ -1134,7 +1134,7 @@ public final class SSLSocketImpl @Override public void close() throws IOException { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("Closing input stream"); } @@ -1142,7 +1142,7 @@ public final class SSLSocketImpl SSLSocketImpl.this.close(); } catch (IOException ioe) { // ignore the exception - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("input stream close failed. Debug info only. Exception details:", ioe); } } @@ -1218,7 +1218,7 @@ public final class SSLSocketImpl socketInputRecord.deplete( conContext.isNegotiated && (getSoTimeout() > 0)); } catch (Exception ex) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning( "input stream close depletion failed", ex); } @@ -1327,7 +1327,7 @@ public final class SSLSocketImpl @Override public void close() throws IOException { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("Closing output stream"); } @@ -1335,7 +1335,7 @@ public final class SSLSocketImpl SSLSocketImpl.this.close(); } catch (IOException ioe) { // ignore the exception - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("output stream close failed. Debug info only. Exception details:", ioe); } } @@ -1543,7 +1543,7 @@ public final class SSLSocketImpl if ((conContext.handshakeContext == null) && !conContext.isOutboundClosed() && !conContext.isBroken) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("trigger key update"); } startHandshake(); @@ -1562,7 +1562,7 @@ public final class SSLSocketImpl !conContext.isOutboundClosed() && !conContext.isInboundClosed() && !conContext.isBroken) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("trigger new session ticket"); } conContext.conSession.updateNST = false; @@ -1670,7 +1670,7 @@ public final class SSLSocketImpl * This method never returns normally, it always throws an IOException. */ private void handleException(Exception cause) throws IOException { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("handling exception", cause); } @@ -1747,7 +1747,7 @@ public final class SSLSocketImpl @Override public void shutdown() throws IOException { if (!isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("close the underlying socket"); } @@ -1773,7 +1773,7 @@ public final class SSLSocketImpl } private void closeSocket(boolean selfInitiated) throws IOException { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("close the SSL connection " + (selfInitiated ? "(initiative)" : "(passive)")); } @@ -1828,7 +1828,7 @@ public final class SSLSocketImpl * transport without waiting for the responding close_notify. */ private void waitForClose() throws IOException { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("wait for close_notify or alert"); } @@ -1838,7 +1838,7 @@ public final class SSLSocketImpl try { Plaintext plainText = decode(null); // discard and continue - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest( "discard plaintext while waiting for close", plainText); 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 09223a4485d..ce7ab630730 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, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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. * @@ -210,7 +210,7 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { int contentLen = ((header[3] & 0xFF) << 8) + (header[4] & 0xFF); // pos: 3, 4 - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "READ: " + ProtocolVersion.nameOf(majorVersion, minorVersion) + @@ -243,7 +243,7 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { readFully(contentLen); recordBody.flip(); - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "READ: " + ProtocolVersion.nameOf(majorVersion, minorVersion) + @@ -406,7 +406,7 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { */ os.write(SSLRecord.v2NoCipher); // SSLv2Hello - if (SSLLogger.isOn) { + if (SSLLogger.isOn()) { if (SSLLogger.isOn("record")) { SSLLogger.fine( "Requested to negotiate unsupported SSLv2!"); @@ -445,7 +445,7 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { ByteBuffer converted = convertToClientHello(recordBody); - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine( "[Converted] ClientHello", converted); } @@ -488,13 +488,13 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { private static int read(InputStream is, byte[] buf, int off, int len) throws IOException { int readLen = is.read(buf, off, len); if (readLen < 0) { - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw read: EOF"); } throw new EOFException("SSL peer shut down incorrectly"); } - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { ByteBuffer bb = ByteBuffer.wrap(buf, off, readLen); SSLLogger.fine("Raw read", bb); } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java index a7809754ed0..e83ad15db22 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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 @@ -55,7 +55,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { recordLock.lock(); try { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "alert message: " + Alert.nameOf(description)); } @@ -67,7 +67,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { write(level); write(description); - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine("WRITE: " + protocolVersion.name + " " + ContentType.ALERT.name + "(" + Alert.nameOf(description) + ")" + @@ -81,7 +81,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { deliverStream.write(buf, 0, count); // may throw IOException deliverStream.flush(); // may throw IOException - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw write", (new ByteArrayInputStream(buf, 0, count))); } @@ -99,7 +99,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { recordLock.lock(); try { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "handshake message", ByteBuffer.wrap(source, offset, length)); @@ -127,7 +127,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { int limit = v2ClientHello.limit(); handshakeHash.deliver(record, 2, (limit - 2)); - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "WRITE: SSLv2 ClientHello message" + ", length = " + limit); @@ -141,7 +141,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { deliverStream.write(record, 0, limit); deliverStream.flush(); - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw write", (new ByteArrayInputStream(record, 0, limit))); } @@ -177,7 +177,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { return; } - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "WRITE: " + protocolVersion.name + " " + ContentType.HANDSHAKE.name + @@ -191,7 +191,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { deliverStream.write(buf, 0, count); // may throw IOException deliverStream.flush(); // may throw IOException - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw write", (new ByteArrayInputStream(buf, 0, count))); } @@ -212,7 +212,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { recordLock.lock(); try { if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound has closed, ignore outbound " + "change_cipher_spec message"); } @@ -231,7 +231,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { deliverStream.write(buf, 0, count); // may throw IOException // deliverStream.flush(); // flush in Finished - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw write", (new ByteArrayInputStream(buf, 0, count))); } @@ -257,7 +257,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { return; } - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "WRITE: " + protocolVersion.name + " " + ContentType.HANDSHAKE.name + @@ -271,7 +271,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { deliverStream.write(buf, 0, count); // may throw IOException deliverStream.flush(); // may throw IOException - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw write", (new ByteArrayInputStream(buf, 0, count))); } @@ -293,7 +293,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { } if (writeCipher.authenticator.seqNumOverflow()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine( "sequence number extremely close to overflow " + "(2^64-1 packets). Closing connection."); @@ -330,7 +330,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { count = position; write(source, offset, fragLen); - if (SSLLogger.isOn && SSLLogger.isOn("record")) { + if (SSLLogger.isOn() && SSLLogger.isOn("record")) { SSLLogger.fine( "WRITE: " + protocolVersion.name + " " + ContentType.APPLICATION_DATA.name + @@ -345,7 +345,7 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord { deliverStream.write(buf, 0, count); // may throw IOException deliverStream.flush(); // may throw IOException - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + if (SSLLogger.isOn() && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw write", (new ByteArrayInputStream(buf, 0, count))); } 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 c248b48fb0a..9298e016f63 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -113,7 +113,7 @@ interface SSLTransport { // Code to deliver SSLv2 error message for SSL/TLS connections. if (!context.sslContext.isDTLS()) { context.outputRecord.encodeV2NoCipher(); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("may be talking to SSLv2"); } } @@ -161,7 +161,7 @@ interface SSLTransport { if (context.handshakeContext != null && context.handshakeContext.sslConfig.enableRetransmissions && context.sslContext.isDTLS()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,verbose")) { SSLLogger.finest("retransmitted handshake flight"); } @@ -181,7 +181,7 @@ interface SSLTransport { // Note that JDK does not support 0-RTT yet. Otherwise, it is // needed to check early_data. if (!context.isNegotiated) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,verbose")) { SSLLogger.warning("unexpected application data " + "before handshake completion"); } 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 1d2faa5351f..76c266a628a 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java @@ -365,7 +365,7 @@ final class ServerHello { shc.sslConfig.getEnabledExtensions( SSLHandshake.SERVER_HELLO, shc.negotiatedProtocol); shm.extensions.produce(shc, serverHelloExtensions); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced ServerHello handshake message", shm); } @@ -440,7 +440,7 @@ final class ServerHello { } // The cipher suite has been negotiated. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("use cipher suite " + cs.name); } @@ -453,7 +453,7 @@ final class ServerHello { if (ke != null) { SSLPossession[] hcds = ke.createPossessions(shc); if ((hcds != null) && (hcds.length != 0)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "use legacy cipher suite " + cs.name); } @@ -570,7 +570,7 @@ final class ServerHello { shc.sslConfig.getEnabledExtensions( SSLHandshake.SERVER_HELLO, shc.negotiatedProtocol); shm.extensions.produce(shc, serverHelloExtensions); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Produced ServerHello handshake message", shm); } @@ -723,14 +723,14 @@ final class ServerHello { } // The cipher suite has been negotiated. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("use cipher suite " + cs.name); } return cs; } if (legacySuite != null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "use legacy cipher suite " + legacySuite.name); } @@ -783,7 +783,7 @@ final class ServerHello { shc.sslConfig.getEnabledExtensions( SSLHandshake.HELLO_RETRY_REQUEST, shc.negotiatedProtocol); hhrm.extensions.produce(shc, serverHelloExtensions); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced HelloRetryRequest handshake message", hhrm); } @@ -845,7 +845,7 @@ final class ServerHello { shc.sslConfig.getEnabledExtensions( SSLHandshake.MESSAGE_HASH, shc.negotiatedProtocol); hhrm.extensions.produce(shc, serverHelloExtensions); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Reproduced HelloRetryRequest handshake message", hhrm); } @@ -886,7 +886,7 @@ final class ServerHello { } ServerHelloMessage shm = new ServerHelloMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Consuming ServerHello handshake message", shm); } @@ -931,7 +931,7 @@ final class ServerHello { } chc.negotiatedProtocol = serverVersion; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Negotiated protocol version: " + serverVersion.name); } @@ -986,7 +986,7 @@ final class ServerHello { chc.conContext.protocolVersion = chc.negotiatedProtocol; chc.conContext.outputRecord.setVersion(chc.negotiatedProtocol); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Negotiated protocol version: " + serverVersion.name); } @@ -1132,7 +1132,7 @@ final class ServerHello { chc.handshakeSession = new SSLSessionImpl(chc, chc.negotiatedCipherSuite, newId); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Locally assigned Session Id: " + newId.toString()); } @@ -1204,7 +1204,7 @@ final class ServerHello { private static void setUpPskKD(HandshakeContext hc, SecretKey psk) throws SSLHandshakeException { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Using PSK to derive early secret"); } diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHelloDone.java b/src/java.base/share/classes/sun/security/ssl/ServerHelloDone.java index 7136b36ffc2..a86257ab3d0 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHelloDone.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHelloDone.java @@ -93,7 +93,7 @@ final class ServerHelloDone { ServerHandshakeContext shc = (ServerHandshakeContext)context; ServerHelloDoneMessage shdm = new ServerHelloDoneMessage(shc); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced ServerHelloDone handshake message", shdm); } @@ -147,7 +147,7 @@ final class ServerHelloDone { ServerHelloDoneMessage shdm = new ServerHelloDoneMessage(chc, message); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Consuming ServerHelloDone handshake message", shdm); } diff --git a/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java b/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java index 96c3fe2fa6a..1b3c8ec3eba 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java @@ -216,7 +216,7 @@ final class ServerNameExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(CH_SERVER_NAME)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Ignore unavailable server_name extension"); } @@ -261,7 +261,7 @@ final class ServerNameExtension { return extData; } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("Unable to indicate server name"); } return null; @@ -287,7 +287,7 @@ final class ServerNameExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(CH_SERVER_NAME)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extension: " + CH_SERVER_NAME.name); } @@ -305,7 +305,7 @@ final class ServerNameExtension { if (!shc.sslConfig.sniMatchers.isEmpty()) { sni = chooseSni(shc.sslConfig.sniMatchers, spec.serverNames); if (sni != null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "server name indication (" + sni + ") is accepted"); @@ -322,7 +322,7 @@ final class ServerNameExtension { // connection with a "missing_extension" alert. // // We do not reject client without SNI extension currently. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "no server name matchers, " + "ignore server name indication"); @@ -347,7 +347,7 @@ final class ServerNameExtension { // so don't include the pre-shared key in the // ServerHello handshake message shc.handshakeExtensions.remove(SH_PRE_SHARED_KEY); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "abort session resumption, " + "different server name indication used"); @@ -441,7 +441,7 @@ final class ServerNameExtension { CHServerNamesSpec spec = (CHServerNamesSpec) shc.handshakeExtensions.get(CH_SERVER_NAME); if (spec == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "Ignore unavailable extension: " + SH_SERVER_NAME.name); } @@ -451,7 +451,7 @@ final class ServerNameExtension { // When resuming a session, the server MUST NOT include a // server_name extension in the server hello. if (shc.isResumption || shc.negotiatedServerName == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "No expected server name indication response"); } @@ -528,7 +528,7 @@ final class ServerNameExtension { CHServerNamesSpec spec = (CHServerNamesSpec) shc.handshakeExtensions.get(CH_SERVER_NAME); if (spec == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "Ignore unavailable extension: " + EE_SERVER_NAME.name); } @@ -538,7 +538,7 @@ final class ServerNameExtension { // When resuming a session, the server MUST NOT include a // server_name extension in the server hello. if (shc.isResumption || shc.negotiatedServerName == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest( "No expected server name indication response"); } diff --git a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java index 9a84bbad8fd..1a0283cf859 100644 --- a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java @@ -93,7 +93,7 @@ final class SessionTicketExtension { kt = Integer.parseInt(s) * 1000; // change to ms if (kt < 0 || kt > NewSessionTicket.MAX_TICKET_LIFETIME) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("Invalid timeout for " + "jdk.tls.server.statelessKeyTimeout: " + kt + ". Set to default value " + @@ -103,7 +103,7 @@ final class SessionTicketExtension { } } catch (NumberFormatException e) { kt = TIMEOUT_DEFAULT; - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("Invalid timeout for " + "jdk.tls.server.statelessKeyTimeout: " + s + ". Set to default value " + TIMEOUT_DEFAULT + @@ -252,7 +252,7 @@ final class SessionTicketExtension { Integer.BYTES + iv.length + 1, encrypted.length); return result; } catch (Exception e) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Encryption failed." + e); } return new byte[0]; @@ -294,7 +294,7 @@ final class SessionTicketExtension { return out; } catch (Exception e) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Decryption failed." + e); } } @@ -309,7 +309,7 @@ final class SessionTicketExtension { gos.write(input, 0, decompressedLen); gos.finish(); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("decompressed bytes: " + decompressedLen + "; compressed bytes: " + baos.size()); } @@ -328,7 +328,7 @@ final class SessionTicketExtension { new ByteArrayInputStream(bytes))) { byte[] out = gis.readAllBytes(); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("compressed bytes: " + compressedLen + "; decompressed bytes: " + out.length); } @@ -394,7 +394,7 @@ final class SessionTicketExtension { // If the context does not allow stateless tickets, exit if (!((SSLSessionContextImpl)chc.sslContext. engineGetClientSessionContext()).statelessEnabled()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Stateless resumption not supported"); } return null; @@ -406,7 +406,7 @@ final class SessionTicketExtension { if (!chc.isResumption || chc.resumingSession == null || chc.resumingSession.getPskIdentity() == null || chc.resumingSession.getProtocolVersion().useTLS13PlusSpec()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Stateless resumption supported"); } return new byte[0]; @@ -450,7 +450,7 @@ final class SessionTicketExtension { shc.statelessResumption = true; if (buffer.remaining() == 0) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Client accepts session tickets."); } return; @@ -462,11 +462,11 @@ final class SessionTicketExtension { if (b != null) { shc.resumingSession = new SSLSessionImpl(shc, b); shc.isResumption = true; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Valid stateless session ticket found"); } } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Invalid stateless session ticket found"); } } @@ -546,7 +546,7 @@ final class SessionTicketExtension { // Disable stateless resumption if server doesn't send the extension. if (chc.statelessResumption) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.info( "Server doesn't support stateless resumption"); } diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java index b298da05e9a..dddeb523516 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java @@ -182,7 +182,7 @@ final class SignatureAlgorithmsExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable( SSLExtension.CH_SIGNATURE_ALGORITHMS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable signature_algorithms extension"); } @@ -218,7 +218,7 @@ final class SignatureAlgorithmsExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable( SSLExtension.CH_SIGNATURE_ALGORITHMS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable signature_algorithms extension"); } diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java index 5a8f103082b..b91fc17fd29 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java @@ -204,7 +204,7 @@ enum SignatureScheme { NoSuchAlgorithmException | RuntimeException exp) { // Signature.getParameters() may throw RuntimeException. mediator = false; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "RSASSA-PSS signature with " + hash + " is not supported by the underlying providers", exp); @@ -297,7 +297,7 @@ enum SignatureScheme { Signature.getInstance(algorithm); } catch (Exception e) { mediator = false; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Signature algorithm, " + algorithm + ", is not supported by the underlying providers"); @@ -432,7 +432,7 @@ enum SignatureScheme { for (SignatureScheme ss: schemesToCheck) { if (!ss.isAvailable) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Ignore unsupported signature scheme: " + ss.name); @@ -451,12 +451,12 @@ enum SignatureScheme { if (isMatch) { if (ss.isPermitted(constraints, scopes)) { supported.add(ss); - } else if (SSLLogger.isOn && + } else if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Ignore disabled signature scheme: " + ss.name); } - } else if (SSLLogger.isOn && + } else if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Ignore inactive signature scheme: " + ss.name); @@ -476,7 +476,7 @@ enum SignatureScheme { for (int ssid : algorithmIds) { SignatureScheme ss = SignatureScheme.valueOf(ssid); if (ss == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Unsupported signature scheme: " + SignatureScheme.nameOf(ssid)); @@ -486,7 +486,7 @@ enum SignatureScheme { && ss.isAllowed(constraints, protocolVersion, scopes)) { supported.add(ss); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Unsupported signature scheme: " + ss.name); } @@ -545,7 +545,7 @@ enum SignatureScheme { } } - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Ignore the signature algorithm (" + ss + @@ -574,7 +574,7 @@ enum SignatureScheme { } } - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Ignore the legacy signature algorithm (" + ss + @@ -660,7 +660,7 @@ enum SignatureScheme { return signer; } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidAlgorithmParameterException nsae) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest( "Ignore unsupported signature algorithm (" + diff --git a/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java b/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java index ec200c6e495..d8c4a8ccc3e 100644 --- a/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java +++ b/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java @@ -119,13 +119,13 @@ final class StatusResponseManager { if (cert.getExtensionValue( PKIXExtensions.OCSPNoCheck_Id.toString()) != null) { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "OCSP NoCheck extension found. OCSP will be skipped"); } return null; } else if (defaultResponder != null && respOverride) { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "Responder override: URI is " + defaultResponder); } @@ -165,7 +165,7 @@ final class StatusResponseManager { Map responseMap = new HashMap<>(); List requestList = new ArrayList<>(); - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "Beginning check: Type = " + type + ", Chain length = " + chain.length); @@ -192,7 +192,7 @@ final class StatusResponseManager { requestList.add(new OCSPFetchCall(sInfo, ocspReq)); } } catch (IOException exc) { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "Exception during CertId creation: ", exc); } @@ -219,14 +219,14 @@ final class StatusResponseManager { requestList.add(new OCSPFetchCall(sInfo, ocspReq)); } } catch (IOException exc) { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "Exception during CertId creation: ", exc); } } } } else { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine("Unsupported status request type: " + type); } } @@ -257,7 +257,7 @@ final class StatusResponseManager { // that, otherwise just log the ExecutionException Throwable cause = Optional.ofNullable( exc.getCause()).orElse(exc); - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine("Exception during OCSP fetch: " + cause); } @@ -266,13 +266,13 @@ final class StatusResponseManager { if (info != null && info.responseData != null) { responseMap.put(info.cert, info.responseData.ocspBytes); - } else if (SSLLogger.isOn && + } else if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "Completed task had no response data"); } } else { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine("Found cancelled task"); } } @@ -280,7 +280,7 @@ final class StatusResponseManager { } catch (InterruptedException intex) { // Log and reset the interrupted state Thread.currentThread().interrupt(); - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine("Interrupt occurred while fetching: " + intex); } @@ -308,7 +308,7 @@ final class StatusResponseManager { for (Extension ext : ocspRequest.extensions) { if (ext.getId().equals( PKIXExtensions.OCSPNonce_Id.toString())) { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "Nonce extension found, skipping cache check"); } @@ -323,14 +323,14 @@ final class StatusResponseManager { // and do not return it as a cache hit. if (respEntry != null && respEntry.nextUpdate != null && respEntry.nextUpdate.before(new Date())) { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "nextUpdate threshold exceeded, purging from cache"); } respEntry = null; } - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "Check cache for SN" + Debug.toString(cid.getSerialNumber()) + ": " + (respEntry != null ? "HIT" : "MISS")); @@ -493,7 +493,7 @@ final class StatusResponseManager { */ @Override public StatusInfo call() { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "Starting fetch for SN " + Debug.toString(statInfo.cid.getSerialNumber())); @@ -505,13 +505,13 @@ final class StatusResponseManager { if (statInfo.responder == null) { // If we have no URI then there's nothing to do // but return. - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "Null URI detected, OCSP fetch aborted"); } return statInfo; } else { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "Attempting fetch from " + statInfo.responder); } @@ -541,7 +541,7 @@ final class StatusResponseManager { statInfo.cid); // Get the response status and act on it appropriately - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine("OCSP Status: " + cacheEntry.status + " (" + respBytes.length + " bytes)"); } @@ -554,7 +554,7 @@ final class StatusResponseManager { addToCache(statInfo.cid, cacheEntry); } } catch (IOException ioe) { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine("Caught exception: ", ioe); } } @@ -573,12 +573,12 @@ final class StatusResponseManager { // If no cache lifetime has been set on entries then // don't cache this response if there is no nextUpdate field if (entry.nextUpdate == null && cacheLifetime == 0) { - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine("Not caching this OCSP response"); } } else { responseCache.put(certId, entry); - if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + if (SSLLogger.isOn() && SSLLogger.isOn("respmgr")) { SSLLogger.fine( "Added response for SN " + Debug.toString(certId.getSerialNumber()) + @@ -600,7 +600,7 @@ final class StatusResponseManager { // is necessary. Also, we will only staple if we're doing a full // handshake. if (!shc.sslContext.isStaplingEnabled(false) || shc.isResumption) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Staping disabled or is a resumed session"); } return null; @@ -623,7 +623,7 @@ final class StatusResponseManager { // selection yet, only accept a request if the ResponderId field // is empty. Finally, we'll only do this in (D)TLS 1.2 or earlier. if (statReqV2 != null && !shc.negotiatedProtocol.useTLS13PlusSpec()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.fine("SH Processing status_request_v2 extension"); } // RFC 6961 stapling @@ -660,7 +660,7 @@ final class StatusResponseManager { req = reqItems[ocspIdx]; type = CertStatusRequestType.valueOf(req.statusType); } else { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest("Warning: No suitable request " + "found in the status_request_v2 extension."); @@ -678,7 +678,7 @@ final class StatusResponseManager { // we will try processing an asserted status_request. if ((statReq != null) && (ext == null || type == null || req == null)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.fine("SH Processing status_request extension"); } ext = SSLExtension.CH_STATUS_REQUEST; @@ -692,7 +692,7 @@ final class StatusResponseManager { if (ocspReq.responderIds.isEmpty()) { req = ocspReq; } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest("Warning: No suitable request " + "found in the status_request extension."); } @@ -704,7 +704,7 @@ final class StatusResponseManager { // find a suitable StatusRequest, then stapling is disabled. // The ext, type and req variables must have been set to continue. if (type == null || req == null || ext == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("No suitable status_request or " + "status_request_v2, stapling is disabled"); } @@ -721,7 +721,7 @@ final class StatusResponseManager { } if (x509Possession == null) { // unlikely - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest("Warning: no X.509 certificates found. " + "Stapling is disabled."); } @@ -743,7 +743,7 @@ final class StatusResponseManager { responses = statRespMgr.get(fetchType, req, certs, shc.statusRespTimeout, TimeUnit.MILLISECONDS); if (!responses.isEmpty()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest("Response manager returned " + responses.size() + " entries."); } @@ -752,7 +752,7 @@ final class StatusResponseManager { if (type == CertStatusRequestType.OCSP) { byte[] respDER = responses.get(certs[0]); if (respDER == null || respDER.length == 0) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest("Warning: Null or zero-length " + "response found for leaf certificate. " + @@ -763,7 +763,7 @@ final class StatusResponseManager { } params = new StaplingParameters(ext, type, req, responses); } else { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest("Warning: no OCSP responses obtained. " + "Stapling is disabled."); } @@ -771,7 +771,7 @@ final class StatusResponseManager { } else { // This should not happen, but if lazy initialization of the // StatusResponseManager doesn't occur we should turn off stapling. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.finest("Warning: lazy initialization " + "of the StatusResponseManager failed. " + "Stapling is disabled."); diff --git a/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java b/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java index 6bf138f4e45..1fa2356d1de 100644 --- a/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java @@ -129,7 +129,7 @@ final class SunX509KeyManagerImpl extends X509KeyManagerCertChecking { X509Credentials cred = new X509Credentials((PrivateKey) key, (X509Certificate[]) certs); credentialsMap.put(alias, cred); - if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("keymanager")) { SSLLogger.fine("found key for : " + alias, (Object[]) certs); } } @@ -315,7 +315,7 @@ final class SunX509KeyManagerImpl extends X509KeyManagerCertChecking { } if (results == null) { - if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("keymanager")) { SSLLogger.fine("KeyMgr: no matching key found"); } return null; diff --git a/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java index 57e5f8c9093..67cb37988a1 100644 --- a/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java @@ -164,7 +164,7 @@ final class SupportedGroupsExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(CH_SUPPORTED_GROUPS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable supported_groups extension"); } @@ -177,7 +177,7 @@ final class SupportedGroupsExtension { for (String name : chc.sslConfig.namedGroups) { NamedGroup ng = NamedGroup.nameOf(name); if (ng == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unspecified named group: " + name); } @@ -193,14 +193,14 @@ final class SupportedGroupsExtension { ng.isSupported(chc.activeCipherSuites) && ng.isPermitted(chc.algorithmConstraints)) { namedGroups.add(ng); - } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + } else if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore inactive or disabled named group: " + ng.name); } } if (namedGroups.isEmpty()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("no available named group"); } @@ -244,7 +244,7 @@ final class SupportedGroupsExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(CH_SUPPORTED_GROUPS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable supported_groups extension"); } @@ -319,7 +319,7 @@ final class SupportedGroupsExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(EE_SUPPORTED_GROUPS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable supported_groups extension"); } @@ -335,7 +335,7 @@ final class SupportedGroupsExtension { for (String name : shc.sslConfig.namedGroups) { NamedGroup ng = NamedGroup.nameOf(name); if (ng == null) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unspecified named group: " + name); @@ -352,14 +352,14 @@ final class SupportedGroupsExtension { ng.isSupported(shc.activeCipherSuites) && ng.isPermitted(shc.algorithmConstraints)) { namedGroups.add(ng); - } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + } else if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore inactive or disabled named group: " + ng.name); } } if (namedGroups.isEmpty()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("no available named group"); } @@ -399,7 +399,7 @@ final class SupportedGroupsExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(EE_SUPPORTED_GROUPS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable supported_groups extension"); } diff --git a/src/java.base/share/classes/sun/security/ssl/SupportedVersionsExtension.java b/src/java.base/share/classes/sun/security/ssl/SupportedVersionsExtension.java index 6efdcef0d29..58597c3008c 100644 --- a/src/java.base/share/classes/sun/security/ssl/SupportedVersionsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SupportedVersionsExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -168,7 +168,7 @@ final class SupportedVersionsExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(CH_SUPPORTED_VERSIONS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extension: " + CH_SUPPORTED_VERSIONS.name); @@ -216,7 +216,7 @@ final class SupportedVersionsExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(CH_SUPPORTED_VERSIONS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extension: " + CH_SUPPORTED_VERSIONS.name); @@ -308,7 +308,7 @@ final class SupportedVersionsExtension { shc.handshakeExtensions.get(CH_SUPPORTED_VERSIONS); if (svs == null) { // Unlikely, no key_share extension requested. - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( "Ignore unavailable supported_versions extension"); } @@ -317,7 +317,7 @@ final class SupportedVersionsExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(SH_SUPPORTED_VERSIONS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extension: " + SH_SUPPORTED_VERSIONS.name); @@ -356,7 +356,7 @@ final class SupportedVersionsExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(SH_SUPPORTED_VERSIONS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extension: " + SH_SUPPORTED_VERSIONS.name); @@ -399,7 +399,7 @@ final class SupportedVersionsExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(HRR_SUPPORTED_VERSIONS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extension: " + HRR_SUPPORTED_VERSIONS.name); @@ -441,7 +441,7 @@ final class SupportedVersionsExtension { // Is it a supported and enabled extension? if (!chc.sslConfig.isAvailable(HRR_SUPPORTED_VERSIONS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unavailable extension: " + HRR_SUPPORTED_VERSIONS.name); @@ -483,7 +483,7 @@ final class SupportedVersionsExtension { // Is it a supported and enabled extension? if (!shc.sslConfig.isAvailable(HRR_SUPPORTED_VERSIONS)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "[Reproduce] Ignore unavailable extension: " + HRR_SUPPORTED_VERSIONS.name); diff --git a/src/java.base/share/classes/sun/security/ssl/TransportContext.java b/src/java.base/share/classes/sun/security/ssl/TransportContext.java index 9595dc8b3fd..980d9c4a6ce 100644 --- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java +++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java @@ -270,7 +270,7 @@ final class TransportContext implements ConnectionContext { try { outputRecord.encodeAlert(Alert.Level.WARNING.level, alert.id); } catch (IOException ioe) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning( "Warning: failed to send warning alert " + alert, ioe); } @@ -330,7 +330,7 @@ final class TransportContext implements ConnectionContext { // so we'll do it here. if (closeReason != null) { if (cause == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning( "Closed transport, general or untracked problem"); } @@ -341,7 +341,7 @@ final class TransportContext implements ConnectionContext { if (cause instanceof SSLException) { throw (SSLException)cause; } else { // unlikely, but just in case. - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning( "Closed transport, unexpected rethrowing", cause); } @@ -364,7 +364,7 @@ final class TransportContext implements ConnectionContext { } // shutdown the transport - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.severe("Fatal (" + alert + "): " + diagnostic, cause); } @@ -380,7 +380,7 @@ final class TransportContext implements ConnectionContext { try { inputRecord.close(); } catch (IOException ioe) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("Fatal: input record closure failed", ioe); } @@ -411,7 +411,7 @@ final class TransportContext implements ConnectionContext { try { outputRecord.encodeAlert(Alert.Level.FATAL.level, alert.id); } catch (IOException ioe) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning( "Fatal: failed to send fatal alert " + alert, ioe); } @@ -424,7 +424,7 @@ final class TransportContext implements ConnectionContext { try { outputRecord.close(); } catch (IOException ioe) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("Fatal: output record closure failed", ioe); } @@ -440,7 +440,7 @@ final class TransportContext implements ConnectionContext { try { transport.shutdown(); } catch (IOException ioe) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("Fatal: transport closure failed", ioe); } @@ -526,7 +526,7 @@ final class TransportContext implements ConnectionContext { passiveInboundClose(); } } catch (IOException ioe) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("inbound closure failed", ioe); } } @@ -583,7 +583,7 @@ final class TransportContext implements ConnectionContext { try { initiateOutboundClose(); } catch (IOException ioe) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning("outbound closure failed", ioe); } } diff --git a/src/java.base/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java b/src/java.base/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java index bac7735de07..8b89fecefa8 100644 --- a/src/java.base/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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,24 +48,24 @@ abstract class TrustManagerFactoryImpl extends TrustManagerFactorySpi { trustManager = getInstance(TrustStoreManager.getTrustedCerts()); } catch (SecurityException se) { // eat security exceptions but report other throwables - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine( "SunX509: skip default keystore", se); } } catch (Error err) { - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine( "SunX509: skip default keystore", err); } throw err; } catch (RuntimeException re) { - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine( "SunX509: skip default keystore", re); } throw re; } catch (Exception e) { - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine( "SunX509: skip default keystore", e); } diff --git a/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java b/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java index e2c353847c7..a44f3a4e32d 100644 --- a/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java +++ b/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java @@ -108,7 +108,7 @@ final class TrustStoreManager { this.storeFile = storeFile; this.lastModified = lastModified; - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine( "trustStore is: " + storeName + "\n" + "trustStore type is: " + storeType + "\n" + @@ -151,7 +151,7 @@ final class TrustStoreManager { } // Not break, the file is inaccessible. - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine( "Inaccessible trust store: " + @@ -267,7 +267,7 @@ final class TrustStoreManager { } // Reload a new key store. - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine("Reload the trust store"); } @@ -321,7 +321,7 @@ final class TrustStoreManager { // Reload the trust store if needed. if (ks == null) { - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine("Reload the trust store"); } ks = loadKeyStore(descriptor); @@ -329,12 +329,12 @@ final class TrustStoreManager { } // Reload trust certs from the key store. - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine("Reload trust certs"); } certs = loadTrustedCerts(ks); - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine("Reloaded " + certs.size() + " trust certs"); } @@ -355,7 +355,7 @@ final class TrustStoreManager { descriptor.storeFile == null) { // No file available, no KeyStore available. - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine("No available key store"); } @@ -382,7 +382,7 @@ final class TrustStoreManager { ks.load(bis, password); } catch (FileNotFoundException fnfe) { // No file available, no KeyStore available. - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("trustmanager")) { SSLLogger.fine( "Not available key store: " + descriptor.storeName); } diff --git a/src/java.base/share/classes/sun/security/ssl/Utilities.java b/src/java.base/share/classes/sun/security/ssl/Utilities.java index 50cd3bee751..458551b9d8a 100644 --- a/src/java.base/share/classes/sun/security/ssl/Utilities.java +++ b/src/java.base/share/classes/sun/security/ssl/Utilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -70,7 +70,7 @@ final class Utilities { SNIServerName serverName = sniList.get(i); if (serverName.getType() == StandardConstants.SNI_HOST_NAME) { sniList.set(i, sniHostName); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine( "the previous server name in SNI (" + serverName + ") was replaced with (" + sniHostName + ")"); @@ -116,7 +116,7 @@ final class Utilities { return new SNIHostName(hostname); } catch (IllegalArgumentException iae) { // don't bother to handle illegal host_name - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine(hostname + "\" " + "is not a legal HostName for server name indication"); } diff --git a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java index 5abc2cb1bf4..6aedff02c34 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java +++ b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java @@ -201,7 +201,7 @@ enum X509Authentication implements SSLAuthentication { private static SSLPossession createClientPossession( ClientHandshakeContext chc, String[] keyTypes) { X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager(); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("X509KeyManager class: " + km.getClass().getName()); } @@ -243,7 +243,7 @@ enum X509Authentication implements SSLAuthentication { } if (clientAlias == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("No X.509 cert selected for " + Arrays.toString(keyTypes)); } @@ -252,7 +252,7 @@ enum X509Authentication implements SSLAuthentication { PrivateKey clientPrivateKey = km.getPrivateKey(clientAlias); if (clientPrivateKey == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest( clientAlias + " is not a private key entry"); } @@ -261,7 +261,7 @@ enum X509Authentication implements SSLAuthentication { X509Certificate[] clientCerts = km.getCertificateChain(clientAlias); if ((clientCerts == null) || (clientCerts.length == 0)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest(clientAlias + " is a private key entry with no cert chain stored"); } @@ -270,7 +270,7 @@ enum X509Authentication implements SSLAuthentication { String privateKeyAlgorithm = clientPrivateKey.getAlgorithm(); if (!Arrays.asList(keyTypes).contains(privateKeyAlgorithm)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine( clientAlias + " private key algorithm " + privateKeyAlgorithm + " not in request list"); @@ -280,7 +280,7 @@ enum X509Authentication implements SSLAuthentication { String publicKeyAlgorithm = clientCerts[0].getPublicKey().getAlgorithm(); if (!privateKeyAlgorithm.equals(publicKeyAlgorithm)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine( clientAlias + " private or public key is not of " + "same algorithm: " + @@ -296,7 +296,7 @@ enum X509Authentication implements SSLAuthentication { private static SSLPossession createServerPossession( ServerHandshakeContext shc, String[] keyTypes) { X509ExtendedKeyManager km = shc.sslContext.getX509KeyManager(); - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("X509KeyManager class: " + km.getClass().getName()); } @@ -337,7 +337,7 @@ enum X509Authentication implements SSLAuthentication { } if (serverAlias == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest("No X.509 cert selected for " + keyType); } continue; @@ -345,7 +345,7 @@ enum X509Authentication implements SSLAuthentication { PrivateKey serverPrivateKey = km.getPrivateKey(serverAlias); if (serverPrivateKey == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest( serverAlias + " is not a private key entry"); } @@ -354,7 +354,7 @@ enum X509Authentication implements SSLAuthentication { X509Certificate[] serverCerts = km.getCertificateChain(serverAlias); if ((serverCerts == null) || (serverCerts.length == 0)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.finest( serverAlias + " is not a certificate entry"); } @@ -364,7 +364,7 @@ enum X509Authentication implements SSLAuthentication { PublicKey serverPublicKey = serverCerts[0].getPublicKey(); if ((!serverPrivateKey.getAlgorithm().equals(keyType)) || (!serverPublicKey.getAlgorithm().equals(keyType))) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine( serverAlias + " private or public key is not of " + keyType + " algorithm"); @@ -379,7 +379,7 @@ enum X509Authentication implements SSLAuthentication { if (!shc.negotiatedProtocol.useTLS13PlusSpec() && keyType.equals("EC")) { if (!(serverPublicKey instanceof ECPublicKey)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning(serverAlias + " public key is not an instance of ECPublicKey"); } @@ -398,7 +398,7 @@ enum X509Authentication implements SSLAuthentication { ((shc.clientRequestedNamedGroups != null) && !shc.clientRequestedNamedGroups.contains(namedGroup))) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.warning( "Unsupported named group (" + namedGroup + ") used in the " + serverAlias + " certificate"); diff --git a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java index 9484ab4f830..2a1f01273bd 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java +++ b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java @@ -116,7 +116,7 @@ abstract class X509KeyManagerCertChecking extends X509ExtendedKeyManager { } if (keyIndex == -1) { - if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("keymanager")) { SSLLogger.fine("Ignore alias " + alias + ": key algorithm does not match"); } @@ -134,7 +134,7 @@ abstract class X509KeyManagerCertChecking extends X509ExtendedKeyManager { } } if (!found) { - if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("keymanager")) { SSLLogger.fine( "Ignore alias " + alias + ": issuers do not match"); @@ -150,7 +150,7 @@ abstract class X509KeyManagerCertChecking extends X509ExtendedKeyManager { !conformsToAlgorithmConstraints(constraints, chain, checkType.getValidator())) { - if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("keymanager")) { SSLLogger.fine("Ignore alias " + alias + ": certificate chain does not conform to " + "algorithm constraints"); @@ -219,7 +219,7 @@ abstract class X509KeyManagerCertChecking extends X509ExtendedKeyManager { checker.init(false); } catch (CertPathValidatorException cpve) { // unlikely to happen - if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("keymanager")) { SSLLogger.fine( "Cannot initialize algorithm constraints checker", cpve); @@ -235,7 +235,7 @@ abstract class X509KeyManagerCertChecking extends X509ExtendedKeyManager { // We don't care about the unresolved critical extensions. checker.check(cert, Collections.emptySet()); } catch (CertPathValidatorException cpve) { - if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("keymanager")) { SSLLogger.fine("Certificate does not conform to " + "algorithm constraints", cert, cpve); } @@ -392,7 +392,7 @@ abstract class X509KeyManagerCertChecking extends X509ExtendedKeyManager { serverName.getEncoded()); } catch (IllegalArgumentException iae) { // unlikely to happen, just in case ... - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("keymanager")) { SSLLogger.fine("Illegal server name: " + serverName); @@ -408,7 +408,7 @@ abstract class X509KeyManagerCertChecking extends X509ExtendedKeyManager { X509TrustManagerImpl.checkIdentity(hostname, cert, idAlgorithm); } catch (CertificateException e) { - if (SSLLogger.isOn && + if (SSLLogger.isOn() && SSLLogger.isOn("keymanager")) { SSLLogger.fine( "Certificate identity does not match " diff --git a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java index c607fe0f25d..72f079db175 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java @@ -228,7 +228,7 @@ final class X509KeyManagerImpl extends X509KeyManagerCertChecking { || (secondDot - firstDot < 2) || (alias.length() - secondDot < 2)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,keymanager")) { SSLLogger.warning("Invalid alias format: " + alias); } return null; @@ -255,7 +255,7 @@ final class X509KeyManagerImpl extends X509KeyManagerCertChecking { NoSuchAlgorithmException | IndexOutOfBoundsException e) { // ignore and only log exception - if (SSLLogger.isOn && SSLLogger.isOn("ssl,keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,keymanager")) { SSLLogger.warning("Exception thrown while getting an alias " + alias + ": " + e); } @@ -295,7 +295,7 @@ final class X509KeyManagerImpl extends X509KeyManagerCertChecking { if (results != null) { for (EntryStatus status : results) { if (status.checkResult == CheckResult.OK) { - if (SSLLogger.isOn + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,keymanager")) { SSLLogger.fine("Choosing key: " + status); } @@ -312,13 +312,13 @@ final class X509KeyManagerImpl extends X509KeyManagerCertChecking { } } if (allResults == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,keymanager")) { SSLLogger.fine("No matching key found"); } return null; } Collections.sort(allResults); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,keymanager")) { SSLLogger.fine( "No good matching key found, " + "returning best match out of", allResults); @@ -358,13 +358,13 @@ final class X509KeyManagerImpl extends X509KeyManagerCertChecking { } } if (allResults == null || allResults.isEmpty()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,keymanager")) { SSLLogger.fine("No matching alias found"); } return null; } Collections.sort(allResults); - if (SSLLogger.isOn && SSLLogger.isOn("ssl,keymanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,keymanager")) { SSLLogger.fine("Getting aliases", allResults); } return toAliases(allResults); diff --git a/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java b/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java index d82b94a1d7d..1bbe0bfb9c7 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java @@ -81,7 +81,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager this.trustedCerts = trustedCerts; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,trustmanager")) { SSLLogger.fine("adding as trusted certificates", (Object[])trustedCerts.toArray(new X509Certificate[0])); } @@ -98,7 +98,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager trustedCerts = v.getTrustedCertificates(); serverValidator = v; - if (SSLLogger.isOn && SSLLogger.isOn("ssl,trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,trustmanager")) { SSLLogger.fine("adding as trusted certificates", (Object[])trustedCerts.toArray(new X509Certificate[0])); } @@ -242,7 +242,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager null, checkClientTrusted ? null : authType); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,trustmanager")) { SSLLogger.fine("Found trusted certificate", trustedChain[trustedChain.length - 1]); } @@ -288,7 +288,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager null, checkClientTrusted ? null : authType); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,trustmanager")) { SSLLogger.fine("Found trusted certificate", trustedChain[trustedChain.length - 1]); } @@ -331,7 +331,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager null, checkClientTrusted ? null : authType); } - if (SSLLogger.isOn && SSLLogger.isOn("ssl,trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,trustmanager")) { SSLLogger.fine("Found trusted certificate", trustedChain[trustedChain.length - 1]); } @@ -365,7 +365,7 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager hostname = new SNIHostName(sniName.getEncoded()); } catch (IllegalArgumentException iae) { // unlikely to happen, just in case ... - if (SSLLogger.isOn && SSLLogger.isOn("ssl,trustmanager")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl,trustmanager")) { SSLLogger.fine("Illegal server name: " + sniName); } } diff --git a/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool.properties b/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool.properties index fb03573a7d5..751e3af9c9c 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool.properties +++ b/src/java.base/share/classes/sun/security/tools/keytool/resources/keytool.properties @@ -321,7 +321,8 @@ Unable.to.parse.denyAfter.string.in.exception.message=Unable to parse denyAfter whose.sigalg.weak=%1$s uses the %2$s signature algorithm which is considered a security risk. whose.key.disabled=%1$s uses a %2$s which is considered a security risk and is disabled. whose.key.weak=%1$s uses a %2$s which is considered a security risk. It will be disabled in a future update. -jks.storetype.warning=The %1$s keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12". +jks.storetype.warning=%1$s uses outdated cryptographic algorithms and will be removed in a future release. Migrate to PKCS12 using:\n\ +keytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12 migrate.keystore.warning=Migrated "%1$s" to %4$s. The %2$s keystore is backed up as "%3$s". backup.keystore.warning=The original keystore "%1$s" is backed up as "%3$s"... importing.keystore.status=Importing keystore %1$s to %2$s... diff --git a/src/java.base/share/classes/sun/security/util/DomainName.java b/src/java.base/share/classes/sun/security/util/DomainName.java index 4f577f1114c..465c155ab87 100644 --- a/src/java.base/share/classes/sun/security/util/DomainName.java +++ b/src/java.base/share/classes/sun/security/util/DomainName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,7 +45,6 @@ import java.util.zip.ZipInputStream; import static java.nio.charset.StandardCharsets.UTF_8; -import jdk.internal.util.StaticProperty; import sun.security.ssl.SSLLogger; /** @@ -193,7 +192,7 @@ class DomainName { } return getRules(tld, new ZipInputStream(pubSuffixStream)); } catch (IOException e) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine( "cannot parse public suffix data for " + tld + ": " + e.getMessage()); @@ -210,7 +209,7 @@ class DomainName { is = new FileInputStream(f); } catch (FileNotFoundException e) { } if (is == null) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl") && + if (SSLLogger.isOn() && SSLLogger.isOn("ssl") && SSLLogger.isOn("trustmanager")) { SSLLogger.fine( "lib/security/public_suffix_list.dat not found"); @@ -231,7 +230,7 @@ class DomainName { } } if (!found) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + if (SSLLogger.isOn() && SSLLogger.isOn("ssl")) { SSLLogger.fine("Domain " + tld + " not found"); } return null; diff --git a/src/java.base/share/classes/sun/security/util/HostnameChecker.java b/src/java.base/share/classes/sun/security/util/HostnameChecker.java index 1374bc6d535..65115c9aeaf 100644 --- a/src/java.base/share/classes/sun/security/util/HostnameChecker.java +++ b/src/java.base/share/classes/sun/security/util/HostnameChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -271,7 +271,7 @@ public class HostnameChecker { name = IDN.toUnicode(IDN.toASCII(name)); template = IDN.toUnicode(IDN.toASCII(template)); } catch (RuntimeException re) { - if (SSLLogger.isOn) { + if (SSLLogger.isOn()) { SSLLogger.fine("Failed to normalize to Unicode: " + re); } @@ -308,7 +308,7 @@ public class HostnameChecker { String template, boolean chainsToPublicCA) { // not ok if it is a single wildcard character or "*." if (template.equals("*") || template.equals("*.")) { - if (SSLLogger.isOn) { + if (SSLLogger.isOn()) { SSLLogger.fine( "Certificate domain name has illegal single " + "wildcard character: " + template); @@ -328,7 +328,7 @@ public class HostnameChecker { // not ok if there is no dot after wildcard (ex: "*com") if (firstDotIndex == -1) { - if (SSLLogger.isOn) { + if (SSLLogger.isOn()) { SSLLogger.fine( "Certificate domain name has illegal wildcard, " + "no dot after wildcard character: " + template); @@ -353,7 +353,7 @@ public class HostnameChecker { // Is it a top-level domain? if (wildcardedDomain.equalsIgnoreCase(templateDomainSuffix)) { - if (SSLLogger.isOn) { + if (SSLLogger.isOn()) { SSLLogger.fine( "Certificate domain name has illegal " + "wildcard for top-level public suffix: " + template); 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 ccc72ea6ea2..942a91d61b8 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -36,12 +36,14 @@ import javax.crypto.interfaces.DHKey; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import javax.crypto.spec.DHPublicKeySpec; +import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import javax.security.auth.DestroyFailedException; import jdk.internal.access.SharedSecrets; import com.sun.crypto.provider.PBKDF2KeyImpl; import sun.security.jca.JCAUtil; +import sun.security.pkcs.PKCS8Key; import sun.security.x509.AlgorithmId; /** @@ -548,6 +550,22 @@ public final class KeyUtil { throw new IOException("No algorithm detected"); } - + // Generic method for zeroing arrays and objects + public static void clear(Object... list) { + for (Object o: list) { + switch (o) { + case byte[] b -> Arrays.fill(b, (byte)0); + case char[] c -> Arrays.fill(c, (char)0); + case PKCS8Key p8 -> p8.clear(); + case PKCS8EncodedKeySpec p8 -> + SharedSecrets.getJavaSecuritySpecAccess().clearEncodedKeySpec(p8); + case PBEKeySpec pbe -> pbe.clearPassword(); + case null -> {} + default -> + throw new IllegalArgumentException( + o.getClass().getName() + " not defined in KeyUtil.clear()"); + } + } + } } diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index 07d4c70fecb..ba6636d7922 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -27,7 +27,6 @@ package sun.security.util; import java.io.IOException; -import sun.security.util.KnownOIDs; import sun.security.x509.AlgorithmId; /** @@ -164,7 +163,10 @@ public final class PBKDF2Parameters { tmp0.putInteger(keyLength); // prf AlgorithmIdentifier {{PBKDF2-PRFs}} - tmp0.write(new AlgorithmId(prf)); + // HmacSHA1 is the default and must not be encoded. + if (!prf.equals(ObjectIdentifier.of(KnownOIDs.HmacSHA1))) { + tmp0.write(new AlgorithmId(prf)); + } // id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} out.putOID(ObjectIdentifier.of(KnownOIDs.PBKDF2)); diff --git a/src/java.base/share/classes/sun/security/util/Pem.java b/src/java.base/share/classes/sun/security/util/Pem.java index 492017eca29..a9b2908bcc9 100644 --- a/src/java.base/share/classes/sun/security/util/Pem.java +++ b/src/java.base/share/classes/sun/security/util/Pem.java @@ -25,13 +25,18 @@ package sun.security.util; +import sun.security.pkcs.PKCS8Key; import sun.security.x509.AlgorithmId; +import javax.crypto.EncryptedPrivateKeyInfo; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; import java.io.*; import java.nio.charset.StandardCharsets; -import java.security.NoSuchAlgorithmException; -import java.security.PEMRecord; -import java.security.Security; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; import java.util.Base64; import java.util.HexFormat; @@ -145,6 +150,9 @@ public class Pem { * Read the PEM text and return it in it's three components: header, * base64, and footer. * + * The header begins processing when "-----B" is read. At that point + * exceptions will be thrown for syntax errors. + * * The method will leave the stream after reading the end of line of the * footer or end of file * @param is an InputStream @@ -159,15 +167,16 @@ public class Pem { * but the read position in the stream is at the end of the block, so * future reads can be successful. */ - public static PEMRecord readPEM(InputStream is, boolean shortHeader) + public static PEM readPEM(InputStream is, boolean shortHeader) throws IOException { Objects.requireNonNull(is); int hyphen = (shortHeader ? 1 : 0); int eol = 0; - ByteArrayOutputStream os = new ByteArrayOutputStream(6); - // Find starting hyphens + + // Find 5 hyphens followed by a 'B' to start processing the header. + boolean headerStarted = false; do { int d = is.read(); switch (d) { @@ -178,13 +187,20 @@ public class Pem { } throw new EOFException("No PEM data found"); } + case 'B' -> { + if (hyphen == 5) { + headerStarted = true; + } else { + hyphen = 0; + } + } default -> hyphen = 0; } os.write(d); - } while (hyphen != 5); + } while (!headerStarted); StringBuilder sb = new StringBuilder(64); - sb.append("-----"); + sb.append("-----B"); hyphen = 0; int c; @@ -307,14 +323,14 @@ public class Pem { // If there was data before finding the 5 dashes of the PEM header, // backup 5 characters and save that data. byte[] preData = null; - if (os.size() > 5) { - preData = Arrays.copyOf(os.toByteArray(), os.size() - 5); + if (os.size() > 6) { + preData = Arrays.copyOf(os.toByteArray(), os.size() - 6); } - return new PEMRecord(typeConverter(headerType), data, preData); + return new PEM(typeConverter(headerType), data, preData); } - public static PEMRecord readPEM(InputStream is) throws IOException { + public static PEM readPEM(InputStream is) throws IOException { return readPEM(is, false); } @@ -342,8 +358,115 @@ public class Pem { * is not used with this method. * @return PEM in a string */ - public static String pemEncoded(PEMRecord pem) { + public static String pemEncoded(PEM pem) { String p = pem.content().replaceAll("(.{64})", "$1\r\n"); return pemEncoded(pem.type(), p); } + + /* + * Get PKCS8 encoding from an encrypted private key encoding. + */ + public static byte[] decryptEncoding(byte[] encoded, char[] password) + throws GeneralSecurityException { + EncryptedPrivateKeyInfo ekpi; + + Objects.requireNonNull(password, "password cannot be null"); + PBEKeySpec keySpec = new PBEKeySpec(password); + try { + ekpi = new EncryptedPrivateKeyInfo(encoded); + return decryptEncoding(ekpi, keySpec); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } finally { + keySpec.clearPassword(); + } + } + + public static byte[] decryptEncoding(EncryptedPrivateKeyInfo ekpi, PBEKeySpec keySpec) + throws NoSuchAlgorithmException, InvalidKeyException { + + PKCS8EncodedKeySpec p8KeySpec = null; + try { + SecretKeyFactory skf = SecretKeyFactory.getInstance(ekpi.getAlgName()); + p8KeySpec = ekpi.getKeySpec(skf.generateSecret(keySpec)); + return p8KeySpec.getEncoded(); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException(e); + } finally { + KeyUtil.clear(p8KeySpec); + } + } + + + /** + * With a given PKCS8 encoding, construct a PrivateKey or KeyPair. A + * KeyPair is returned if requested and the encoding has a public key; + * otherwise, a PrivateKey is returned. + * + * @param encoded PKCS8 encoding + * @param pair set to true for returning a KeyPair, if possible. Otherwise, + * return a PrivateKey + * @param provider KeyFactory provider + */ + public static DEREncodable toDEREncodable(byte[] encoded, boolean pair, + Provider provider) throws InvalidKeyException { + + PrivateKey privKey; + PublicKey pubKey = null; + PKCS8EncodedKeySpec p8KeySpec; + PKCS8Key p8key = new PKCS8Key(encoded); + KeyFactory kf; + + try { + p8KeySpec = new PKCS8EncodedKeySpec(encoded); + } catch (NullPointerException e) { + p8key.clear(); + throw new InvalidKeyException("No encoding found", e); + } + + try { + if (provider == null) { + kf = KeyFactory.getInstance(p8key.getAlgorithm()); + } else { + kf = KeyFactory.getInstance(p8key.getAlgorithm(), provider); + } + } catch (NoSuchAlgorithmException e) { + KeyUtil.clear(p8KeySpec, p8key); + throw new InvalidKeyException("Unable to find the algorithm: " + + p8key.getAlgorithm(), e); + } + + try { + privKey = kf.generatePrivate(p8KeySpec); + + // Only want the PrivateKey? then return it. + if (!pair) { + return privKey; + } + + if (p8key.hasPublicKey()) { + // PKCS8Key.decode() has extracted the public key already + pubKey = kf.generatePublic( + new X509EncodedKeySpec(p8key.getPubKeyEncoded())); + } else { + // In case decode() could not read the public key, the + // KeyFactory can try. Failure is ok as there may not + // be a public key in the encoding. + try { + pubKey = kf.generatePublic(p8KeySpec); + } catch (InvalidKeySpecException e) { + // ignore + } + } + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException(e); + } finally { + KeyUtil.clear(p8KeySpec, p8key); + } + if (pair && pubKey != null) { + return new KeyPair(pubKey, privKey); + } + return privKey; + } + } diff --git a/src/java.base/share/classes/sun/security/util/SliceableSecretKey.java b/src/java.base/share/classes/sun/security/util/SliceableSecretKey.java new file mode 100644 index 00000000000..4dc3fe0a3e8 --- /dev/null +++ b/src/java.base/share/classes/sun/security/util/SliceableSecretKey.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025, 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.util; + +import javax.crypto.SecretKey; + +/** + * An interface for SecretKeys that support using its slice as a new + * SecretKey. + *

    + * This is mainly used by PKCS #11 implementations that support the + * EXTRACT_KEY_FROM_KEY mechanism even if the key itself is sensitive + * and non-extractable. + */ +public interface SliceableSecretKey { + + /** + * Returns a slice as a new SecretKey. + * + * @param alg the new algorithm name + * @param from the byte offset of the new key in the full key + * @param to the to offset (exclusive) of the new key in the full key + * @return the new key + * @throws ArrayIndexOutOfBoundsException for improper from + * and to values + * @throws UnsupportedOperationException if slicing is not supported + */ + SecretKey slice(String alg, int from, int to); +} diff --git a/src/java.base/share/classes/sun/util/locale/BaseLocale.java b/src/java.base/share/classes/sun/util/locale/BaseLocale.java index 529ca1b0c13..91efc61d1bf 100644 --- a/src/java.base/share/classes/sun/util/locale/BaseLocale.java +++ b/src/java.base/share/classes/sun/util/locale/BaseLocale.java @@ -92,8 +92,8 @@ public final class BaseLocale { } // Interned BaseLocale cache - private static final Supplier> CACHE = - StableValue.supplier(new Supplier<>() { + private static final LazyConstant> CACHE = + LazyConstant.of(new Supplier<>() { @Override public ReferencedKeySet get() { return ReferencedKeySet.create(true, ReferencedKeySet.concurrentHashMapSupplier()); diff --git a/src/java.base/share/classes/sun/util/resources/BreakIteratorResourceBundle.java b/src/java.base/share/classes/sun/util/resources/BreakIteratorResourceBundle.java index d7c575962f6..49e882c5ca6 100644 --- a/src/java.base/share/classes/sun/util/resources/BreakIteratorResourceBundle.java +++ b/src/java.base/share/classes/sun/util/resources/BreakIteratorResourceBundle.java @@ -50,7 +50,7 @@ public abstract class BreakIteratorResourceBundle extends ResourceBundle { // those keys must be added to NON_DATA_KEYS. private static final Set NON_DATA_KEYS = Set.of("BreakIteratorClasses"); - private final Supplier> keys = StableValue.supplier( + private final LazyConstant> keys = LazyConstant.of( new Supplier<>() { public Set get() { return keys0(); }}); private Set keys0() { diff --git a/src/java.base/share/classes/sun/util/resources/OpenListResourceBundle.java b/src/java.base/share/classes/sun/util/resources/OpenListResourceBundle.java index 0c16f508018..9d0c1c015ce 100644 --- a/src/java.base/share/classes/sun/util/resources/OpenListResourceBundle.java +++ b/src/java.base/share/classes/sun/util/resources/OpenListResourceBundle.java @@ -119,7 +119,7 @@ public abstract class OpenListResourceBundle extends ResourceBundle { return new HashSet<>(); } - private final Supplier> lookup = StableValue.supplier( + private final LazyConstant> lookup = LazyConstant.of( new Supplier<>() { public Map get() { return lookup0(); }}); private Map lookup0() { @@ -134,7 +134,7 @@ public abstract class OpenListResourceBundle extends ResourceBundle { return temp; } - private final Supplier> keyset = StableValue.supplier( + private final LazyConstant> keyset = LazyConstant.of( new Supplier<>() { public Set get() { return keyset0(); }}); private Set keyset0() { diff --git a/src/java.base/share/data/lsrdata/language-subtag-registry.txt b/src/java.base/share/data/lsrdata/language-subtag-registry.txt index 64c40f28162..82618f9b40e 100644 --- a/src/java.base/share/data/lsrdata/language-subtag-registry.txt +++ b/src/java.base/share/data/lsrdata/language-subtag-registry.txt @@ -1,4 +1,4 @@ -File-Date: 2025-05-15 +File-Date: 2025-08-25 %% Type: language Subtag: aa @@ -3102,6 +3102,7 @@ Added: 2009-07-29 Type: language Subtag: asb Description: Assiniboine +Description: Nakoda Assiniboine Added: 2009-07-29 %% Type: language @@ -3269,6 +3270,7 @@ Added: 2009-07-29 Type: language Subtag: atj Description: Atikamekw +Description: Nehirowimowin Added: 2009-07-29 %% Type: language @@ -7981,6 +7983,7 @@ Added: 2009-07-29 Type: language Subtag: clc Description: Chilcotin +Description: Tsilhqot’in Added: 2009-07-29 %% Type: language @@ -8021,6 +8024,7 @@ Added: 2009-07-29 %% Type: language Subtag: clm +Description: Klallam Description: Clallam Added: 2009-07-29 %% @@ -13509,7 +13513,7 @@ Added: 2009-07-29 %% Type: language Subtag: haa -Description: Han +Description: Hän Added: 2009-07-29 %% Type: language @@ -19022,6 +19026,7 @@ Added: 2009-07-29 %% Type: language Subtag: kwk +Description: Kwak'wala Description: Kwakiutl Added: 2009-07-29 %% @@ -22262,7 +22267,7 @@ Added: 2009-07-29 %% Type: language Subtag: mhn -Description: Mócheno +Description: Mòcheno Added: 2009-07-29 %% Type: language @@ -31655,6 +31660,7 @@ Added: 2009-07-29 Type: language Subtag: sec Description: Sechelt +Description: She shashishalhem Added: 2009-07-29 %% Type: language @@ -32003,6 +32009,7 @@ Added: 2009-07-29 Type: language Subtag: shs Description: Shuswap +Description: Secwepemctsín Added: 2009-07-29 %% Type: language @@ -33014,6 +33021,7 @@ Added: 2009-07-29 Type: language Subtag: squ Description: Squamish +Description: Sḵwx̱wú7mesh sníchim Added: 2009-07-29 %% Type: language @@ -34664,6 +34672,8 @@ Added: 2009-07-29 Type: language Subtag: thp Description: Thompson +Description: Nłeʔkepmxcín +Description: Thompson River Salish Added: 2009-07-29 %% Type: language @@ -34684,6 +34694,7 @@ Added: 2009-07-29 Type: language Subtag: tht Description: Tahltan +Description: Tāłtān Added: 2009-07-29 %% Type: language @@ -42419,7 +42430,7 @@ Added: 2009-07-29 %% Type: language Subtag: zmp -Description: Mpuono +Description: Mbuun Added: 2009-07-29 %% Type: language @@ -47639,6 +47650,12 @@ Comments: Denotes conventions established by the Academia Brasileira de Letras in 1943 and generally used in Brazil until 2009 %% Type: variant +Subtag: akhmimic +Description: Akhmimic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: akuapem Description: Akuapem Twi Added: 2017-06-05 @@ -47814,6 +47831,12 @@ Comments: Black American Sign Language (BASL) or Black Sign Variation (BSV) is a dialect of American Sign Language (ASL) %% Type: variant +Subtag: bohairic +Description: Bohairic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: bohoric Description: Slovene in Bohorič alphabet Added: 2012-06-27 @@ -47898,6 +47921,12 @@ Comments: Represents the standard written form of Ladin in Fascia which unified the three subvarieties Cazet, Brach and Moenat %% Type: variant +Subtag: fayyumic +Description: Fayyumic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: fodom Description: Fodom standard of Ladin Added: 2024-03-04 @@ -48167,6 +48196,12 @@ Comments: Russian orthography as established by the 1917/1918 orthographic reforms %% Type: variant +Subtag: lycopol +Description: Lycopolitan alias Subakhmimic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: mdcegyp Description: Ancient Egyptian hieroglyphs encoded in Manuel de Codage Added: 2025-02-06 @@ -48180,6 +48215,12 @@ Added: 2025-02-06 Prefix: egy %% Type: variant +Subtag: mesokem +Description: Mesokemic alias Oxyrhynchite dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: metelko Description: Slovene in Metelko alphabet Added: 2012-06-27 @@ -48367,6 +48408,12 @@ Prefix: rm Comments: Supraregional Romansh written standard %% Type: variant +Subtag: sahidic +Description: Sahidic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: saigon Description: The Sài Gòn variant of Vietnamese Added: 2025-03-10 @@ -48555,6 +48602,12 @@ Comments: The subtag represents the old orthography of the Latvian language used during c. 1600s–1920s. %% Type: variant +Subtag: viennese +Description: The Viennese dialect of German +Added: 2025-06-22 +Prefix: de +%% +Type: variant Subtag: vivaraup Description: Vivaro-Alpine Added: 2018-04-22 diff --git a/src/java.base/share/data/unicodedata/Blocks.txt b/src/java.base/share/data/unicodedata/Blocks.txt index 19460657ac9..5c24ab60cb1 100644 --- a/src/java.base/share/data/unicodedata/Blocks.txt +++ b/src/java.base/share/data/unicodedata/Blocks.txt @@ -1,6 +1,6 @@ -# Blocks-16.0.0.txt -# Date: 2024-02-02 -# Copyright (c) 2024 Unicode, Inc. +# Blocks-17.0.0.txt +# Date: 2025-08-01 +# © 2025 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use and license, see https://www.unicode.org/terms_of_use.html # @@ -228,6 +228,7 @@ FFF0..FFFF; Specials 108E0..108FF; Hatran 10900..1091F; Phoenician 10920..1093F; Lydian +10940..1095F; Sidetic 10980..1099F; Meroitic Hieroglyphs 109A0..109FF; Meroitic Cursive 10A00..10A5F; Kharoshthi @@ -279,11 +280,13 @@ FFF0..FFFF; Specials 11AB0..11ABF; Unified Canadian Aboriginal Syllabics Extended-A 11AC0..11AFF; Pau Cin Hau 11B00..11B5F; Devanagari Extended-A +11B60..11B7F; Sharada Supplement 11BC0..11BFF; Sunuwar 11C00..11C6F; Bhaiksuki 11C70..11CBF; Marchen 11D00..11D5F; Masaram Gondi 11D60..11DAF; Gunjala Gondi +11DB0..11DEF; Tolong Siki 11EE0..11EFF; Makasar 11F00..11F5F; Kawi 11FB0..11FBF; Lisu Supplement @@ -304,12 +307,14 @@ FFF0..FFFF; Specials 16B00..16B8F; Pahawh Hmong 16D40..16D7F; Kirat Rai 16E40..16E9F; Medefaidrin +16EA0..16EDF; Beria Erfe 16F00..16F9F; Miao 16FE0..16FFF; Ideographic Symbols and Punctuation 17000..187FF; Tangut 18800..18AFF; Tangut Components 18B00..18CFF; Khitan Small Script 18D00..18D7F; Tangut Supplement +18D80..18DFF; Tangut Components Supplement 1AFF0..1AFFF; Kana Extended-B 1B000..1B0FF; Kana Supplement 1B100..1B12F; Kana Extended-A @@ -318,6 +323,7 @@ FFF0..FFFF; Specials 1BC00..1BC9F; Duployan 1BCA0..1BCAF; Shorthand Format Controls 1CC00..1CEBF; Symbols for Legacy Computing Supplement +1CEC0..1CEFF; Miscellaneous Symbols Supplement 1CF00..1CFCF; Znamenny Musical Notation 1D000..1D0FF; Byzantine Musical Symbols 1D100..1D1FF; Musical Symbols @@ -336,6 +342,7 @@ FFF0..FFFF; Specials 1E2C0..1E2FF; Wancho 1E4D0..1E4FF; Nag Mundari 1E5D0..1E5FF; Ol Onal +1E6C0..1E6FF; Tai Yo 1E7E0..1E7FF; Ethiopic Extended-B 1E800..1E8DF; Mende Kikakui 1E900..1E95F; Adlam @@ -367,6 +374,7 @@ FFF0..FFFF; Specials 2F800..2FA1F; CJK Compatibility Ideographs Supplement 30000..3134F; CJK Unified Ideographs Extension G 31350..323AF; CJK Unified Ideographs Extension H +323B0..3347F; CJK Unified Ideographs Extension J E0000..E007F; Tags E0100..E01EF; Variation Selectors Supplement F0000..FFFFF; Supplementary Private Use Area-A diff --git a/src/java.base/share/data/unicodedata/CaseFolding.txt b/src/java.base/share/data/unicodedata/CaseFolding.txt index 345c4f3dd03..a0b0f07fd64 100644 --- a/src/java.base/share/data/unicodedata/CaseFolding.txt +++ b/src/java.base/share/data/unicodedata/CaseFolding.txt @@ -1,6 +1,6 @@ -# CaseFolding-16.0.0.txt -# Date: 2024-04-30, 21:48:11 GMT -# © 2024 Unicode®, Inc. +# CaseFolding-17.0.0.txt +# Date: 2025-07-30, 23:54:36 GMT +# © 2025 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use and license, see https://www.unicode.org/terms_of_use.html # @@ -18,15 +18,15 @@ # The data supports both implementations that require simple case foldings # (where string lengths don't change), and implementations that allow full case folding # (where string lengths may grow). Note that where they can be supported, the -# full case foldings are superior: for example, they allow "MASSE" and "Maße" to match. +# full case foldings are superior: for example, they allow "FUSS" and "Fuß" to match. # # All code points not listed in this file map to themselves. # # NOTE: case folding does not preserve normalization formats! # # For information on case folding, including how to have case folding -# preserve normalization formats, see Section 3.13 Default Case Algorithms in -# The Unicode Standard. +# preserve normalization formats, see the +# "Conformance" / "Default Case Algorithms" section of the core specification. # # ================================================================================ # Format @@ -1243,7 +1243,10 @@ A7C7; C; A7C8; # LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9; C; A7CA; # LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY A7CB; C; 0264; # LATIN CAPITAL LETTER RAMS HORN A7CC; C; A7CD; # LATIN CAPITAL LETTER S WITH DIAGONAL STROKE +A7CE; C; A7CF; # LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE A7D0; C; A7D1; # LATIN CAPITAL LETTER CLOSED INSULAR G +A7D2; C; A7D3; # LATIN CAPITAL LETTER DOUBLE THORN +A7D4; C; A7D5; # LATIN CAPITAL LETTER DOUBLE WYNN A7D6; C; A7D7; # LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8; C; A7D9; # LATIN CAPITAL LETTER SIGMOID S A7DA; C; A7DB; # LATIN CAPITAL LETTER LAMBDA @@ -1616,6 +1619,31 @@ FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z 16E5D; C; 16E7D; # MEDEFAIDRIN CAPITAL LETTER O 16E5E; C; 16E7E; # MEDEFAIDRIN CAPITAL LETTER AI 16E5F; C; 16E7F; # MEDEFAIDRIN CAPITAL LETTER Y +16EA0; C; 16EBB; # BERIA ERFE CAPITAL LETTER ARKAB +16EA1; C; 16EBC; # BERIA ERFE CAPITAL LETTER BASIGNA +16EA2; C; 16EBD; # BERIA ERFE CAPITAL LETTER DARBAI +16EA3; C; 16EBE; # BERIA ERFE CAPITAL LETTER EH +16EA4; C; 16EBF; # BERIA ERFE CAPITAL LETTER FITKO +16EA5; C; 16EC0; # BERIA ERFE CAPITAL LETTER GOWAY +16EA6; C; 16EC1; # BERIA ERFE CAPITAL LETTER HIRDEABO +16EA7; C; 16EC2; # BERIA ERFE CAPITAL LETTER I +16EA8; C; 16EC3; # BERIA ERFE CAPITAL LETTER DJAI +16EA9; C; 16EC4; # BERIA ERFE CAPITAL LETTER KOBO +16EAA; C; 16EC5; # BERIA ERFE CAPITAL LETTER LAKKO +16EAB; C; 16EC6; # BERIA ERFE CAPITAL LETTER MERI +16EAC; C; 16EC7; # BERIA ERFE CAPITAL LETTER NINI +16EAD; C; 16EC8; # BERIA ERFE CAPITAL LETTER GNA +16EAE; C; 16EC9; # BERIA ERFE CAPITAL LETTER NGAY +16EAF; C; 16ECA; # BERIA ERFE CAPITAL LETTER OI +16EB0; C; 16ECB; # BERIA ERFE CAPITAL LETTER PI +16EB1; C; 16ECC; # BERIA ERFE CAPITAL LETTER ERIGO +16EB2; C; 16ECD; # BERIA ERFE CAPITAL LETTER ERIGO TAMURA +16EB3; C; 16ECE; # BERIA ERFE CAPITAL LETTER SERI +16EB4; C; 16ECF; # BERIA ERFE CAPITAL LETTER SHEP +16EB5; C; 16ED0; # BERIA ERFE CAPITAL LETTER TATASOUE +16EB6; C; 16ED1; # BERIA ERFE CAPITAL LETTER UI +16EB7; C; 16ED2; # BERIA ERFE CAPITAL LETTER WASSE +16EB8; C; 16ED3; # BERIA ERFE CAPITAL LETTER AY 1E900; C; 1E922; # ADLAM CAPITAL LETTER ALIF 1E901; C; 1E923; # ADLAM CAPITAL LETTER DAALI 1E902; C; 1E924; # ADLAM CAPITAL LETTER LAAM @@ -1651,4 +1679,4 @@ FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z 1E920; C; 1E942; # ADLAM CAPITAL LETTER KPO 1E921; C; 1E943; # ADLAM CAPITAL LETTER SHA # -# EOF \ No newline at end of file +# EOF diff --git a/src/java.base/share/data/unicodedata/DerivedCoreProperties.txt b/src/java.base/share/data/unicodedata/DerivedCoreProperties.txt index 43d7af85c29..f327784bf39 100644 --- a/src/java.base/share/data/unicodedata/DerivedCoreProperties.txt +++ b/src/java.base/share/data/unicodedata/DerivedCoreProperties.txt @@ -1,6 +1,6 @@ -# DerivedCoreProperties-16.0.0.txt -# Date: 2024-05-31, 18:09:32 GMT -# Copyright (c) 2024 Unicode, Inc. +# DerivedCoreProperties-17.0.0.txt +# Date: 2025-07-30, 23:55:08 GMT +# © 2025 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use and license, see https://www.unicode.org/terms_of_use.html # @@ -178,6 +178,7 @@ FF5E ; Math # Sm FULLWIDTH TILDE FFE2 ; Math # Sm FULLWIDTH NOT SIGN FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW 10D8E..10D8F ; Math # Sm [2] GARAY PLUS SIGN..GARAY MINUS SIGN +1CEF0 ; Math # Sm MEDIUM SMALL WHITE CIRCLE WITH HORIZONTAL BAR 1D400..1D454 ; Math # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G 1D456..1D49C ; Math # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A 1D49E..1D49F ; Math # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D @@ -253,8 +254,9 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 1EEA5..1EEA9 ; Math # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH 1EEAB..1EEBB ; Math # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 1EEF0..1EEF1 ; Math # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL +1F8D0..1F8D8 ; Math # Sm [9] LONG RIGHTWARDS ARROW OVER LONG LEFTWARDS ARROW..LONG LEFT RIGHT ARROW WITH DEPENDENT LOBE -# Total code points: 2312 +# Total code points: 2322 # ================================================ @@ -273,8 +275,8 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 01BC..01BF ; Alphabetic # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN 01C0..01C3 ; Alphabetic # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK 01C4..0293 ; Alphabetic # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL -0294 ; Alphabetic # Lo LATIN LETTER GLOTTAL STOP -0295..02AF ; Alphabetic # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +0294..0295 ; Alphabetic # Lo [2] LATIN LETTER GLOTTAL STOP..LATIN LETTER PHARYNGEAL VOICED FRICATIVE +0296..02AF ; Alphabetic # L& [26] LATIN LETTER INVERTED GLOTTAL STOP..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL 02B0..02C1 ; Alphabetic # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP 02C6..02D1 ; Alphabetic # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON 02E0..02E4 ; Alphabetic # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP @@ -344,7 +346,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 0840..0858 ; Alphabetic # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN 0860..086A ; Alphabetic # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 0870..0887 ; Alphabetic # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT -0889..088E ; Alphabetic # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL +0889..088F ; Alphabetic # Lo [7] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC LETTER NOON WITH RING ABOVE 0897 ; Alphabetic # Mn ARABIC PEPET 08A0..08C8 ; Alphabetic # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; Alphabetic # Lm ARABIC SMALL FARSI YEH @@ -477,7 +479,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 0C4A..0C4C ; Alphabetic # Mn [3] TELUGU VOWEL SIGN O..TELUGU VOWEL SIGN AU 0C55..0C56 ; Alphabetic # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK 0C58..0C5A ; Alphabetic # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA -0C5D ; Alphabetic # Lo TELUGU LETTER NAKAARA POLLU +0C5C..0C5D ; Alphabetic # Lo [2] TELUGU ARCHAIC SHRII..TELUGU LETTER NAKAARA POLLU 0C60..0C61 ; Alphabetic # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL 0C62..0C63 ; Alphabetic # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL 0C80 ; Alphabetic # Lo KANNADA SIGN SPACING CANDRABINDU @@ -497,7 +499,7 @@ FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS A 0CCA..0CCB ; Alphabetic # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO 0CCC ; Alphabetic # Mn KANNADA VOWEL SIGN AU 0CD5..0CD6 ; Alphabetic # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK -0CDD..0CDE ; Alphabetic # Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA +0CDC..0CDE ; Alphabetic # Lo [3] KANNADA ARCHAIC SHRII..KANNADA LETTER FA 0CE0..0CE1 ; Alphabetic # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL 0CE2..0CE3 ; Alphabetic # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL 0CF1..0CF2 ; Alphabetic # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA @@ -833,11 +835,8 @@ A771..A787 ; Alphabetic # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER A788 ; Alphabetic # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; Alphabetic # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; Alphabetic # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CD ; Alphabetic # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE -A7D0..A7D1 ; Alphabetic # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G -A7D3 ; Alphabetic # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7DC ; Alphabetic # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE -A7F2..A7F4 ; Alphabetic # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q +A790..A7DC ; Alphabetic # L& [77] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER LAMBDA WITH STROKE +A7F1..A7F4 ; Alphabetic # Lm [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; Alphabetic # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; Alphabetic # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; Alphabetic # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -1020,6 +1019,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 108F4..108F5 ; Alphabetic # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW 10900..10915 ; Alphabetic # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU 10920..10939 ; Alphabetic # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C +10940..10959 ; Alphabetic # Lo [26] SIDETIC LETTER N01..SIDETIC LETTER N26 10980..109B7 ; Alphabetic # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA 109BE..109BF ; Alphabetic # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN 10A00 ; Alphabetic # Lo KHAROSHTHI LETTER A @@ -1053,7 +1053,9 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 10EAB..10EAC ; Alphabetic # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK 10EB0..10EB1 ; Alphabetic # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE 10EC2..10EC4 ; Alphabetic # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW -10EFC ; Alphabetic # Mn ARABIC COMBINING ALEF OVERLAY +10EC5 ; Alphabetic # Lm ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW +10EC6..10EC7 ; Alphabetic # Lo [2] ARABIC LETTER THIN NOON..ARABIC LETTER YEH WITH FOUR DOTS BELOW +10EFA..10EFC ; Alphabetic # Mn [3] ARABIC DOUBLE VERTICAL BAR BELOW..ARABIC COMBINING ALEF OVERLAY 10F00..10F1C ; Alphabetic # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; Alphabetic # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; Alphabetic # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -1239,6 +1241,12 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 11A97 ; Alphabetic # Mc SOYOMBO SIGN VISARGA 11A9D ; Alphabetic # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; Alphabetic # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11B60 ; Alphabetic # Mn SHARADA VOWEL SIGN OE +11B61 ; Alphabetic # Mc SHARADA VOWEL SIGN OOE +11B62..11B64 ; Alphabetic # Mn [3] SHARADA VOWEL SIGN UE..SHARADA VOWEL SIGN SHORT E +11B65 ; Alphabetic # Mc SHARADA VOWEL SIGN SHORT O +11B66 ; Alphabetic # Mn SHARADA VOWEL SIGN CANDRA E +11B67 ; Alphabetic # Mc SHARADA VOWEL SIGN CANDRA O 11BC0..11BE0 ; Alphabetic # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO 11C00..11C08 ; Alphabetic # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L 11C0A..11C2E ; Alphabetic # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA @@ -1274,6 +1282,9 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 11D95 ; Alphabetic # Mn GUNJALA GONDI SIGN ANUSVARA 11D96 ; Alphabetic # Mc GUNJALA GONDI SIGN VISARGA 11D98 ; Alphabetic # Lo GUNJALA GONDI OM +11DB0..11DD8 ; Alphabetic # Lo [41] TOLONG SIKI LETTER I..TOLONG SIKI LETTER RRH +11DD9 ; Alphabetic # Lm TOLONG SIKI SIGN SELA +11DDA..11DDB ; Alphabetic # Lo [2] TOLONG SIKI SIGN HECAKA..TOLONG SIKI UNGGA 11EE0..11EF2 ; Alphabetic # Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA 11EF3..11EF4 ; Alphabetic # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U 11EF5..11EF6 ; Alphabetic # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O @@ -1311,6 +1322,8 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 16D43..16D6A ; Alphabetic # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU 16D6B..16D6C ; Alphabetic # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16E40..16E7F ; Alphabetic # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16EA0..16EB8 ; Alphabetic # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY +16EBB..16ED3 ; Alphabetic # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY 16F00..16F4A ; Alphabetic # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F4F ; Alphabetic # Mn MIAO SIGN CONSONANT MODIFIER BAR 16F50 ; Alphabetic # Lo MIAO LETTER NASALIZATION @@ -1320,9 +1333,11 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 16FE0..16FE1 ; Alphabetic # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK 16FE3 ; Alphabetic # Lm OLD CHINESE ITERATION MARK 16FF0..16FF1 ; Alphabetic # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY -17000..187F7 ; Alphabetic # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 -18800..18CD5 ; Alphabetic # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18CFF..18D08 ; Alphabetic # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 +16FF2..16FF3 ; Alphabetic # Lm [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER +16FF4..16FF6 ; Alphabetic # Nl [3] YANGQIN SIGN SLOW ONE BEAT..YANGQIN SIGN SLOW TWO BEATS +17000..18CD5 ; Alphabetic # Lo [7382] TANGUT IDEOGRAPH-17000..KHITAN SMALL SCRIPT CHARACTER-18CD5 +18CFF..18D1E ; Alphabetic # Lo [32] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D1E +18D80..18DF2 ; Alphabetic # Lo [115] TANGUT COMPONENT-769..TANGUT COMPONENT-883 1AFF0..1AFF3 ; Alphabetic # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; Alphabetic # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; Alphabetic # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -1387,6 +1402,17 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 1E4EB ; Alphabetic # Lm NAG MUNDARI SIGN OJOD 1E5D0..1E5ED ; Alphabetic # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG 1E5F0 ; Alphabetic # Lo OL ONAL SIGN HODDOND +1E6C0..1E6DE ; Alphabetic # Lo [31] TAI YO LETTER LOW KO..TAI YO LETTER HIGH KVO +1E6E0..1E6E2 ; Alphabetic # Lo [3] TAI YO LETTER AA..TAI YO LETTER UE +1E6E3 ; Alphabetic # Mn TAI YO SIGN UE +1E6E4..1E6E5 ; Alphabetic # Lo [2] TAI YO LETTER U..TAI YO LETTER AE +1E6E6 ; Alphabetic # Mn TAI YO SIGN AU +1E6E7..1E6ED ; Alphabetic # Lo [7] TAI YO LETTER O..TAI YO LETTER AUE +1E6EE..1E6EF ; Alphabetic # Mn [2] TAI YO SIGN AY..TAI YO SIGN ANG +1E6F0..1E6F4 ; Alphabetic # Lo [5] TAI YO LETTER AN..TAI YO LETTER AP +1E6F5 ; Alphabetic # Mn TAI YO SIGN OM +1E6FE ; Alphabetic # Lo TAI YO SYMBOL MUEANG +1E6FF ; Alphabetic # Lm TAI YO XAM LAI 1E7E0..1E7E6 ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; Alphabetic # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; Alphabetic # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -1432,16 +1458,15 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 1F150..1F169 ; Alphabetic # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F170..1F189 ; Alphabetic # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z 20000..2A6DF ; Alphabetic # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF -2A700..2B739 ; Alphabetic # Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 -2B740..2B81D ; Alphabetic # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D -2B820..2CEA1 ; Alphabetic # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2A700..2B81D ; Alphabetic # Lo [4382] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B81D +2B820..2CEAD ; Alphabetic # Lo [5774] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEAD 2CEB0..2EBE0 ; Alphabetic # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 2EBF0..2EE5D ; Alphabetic # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D 2F800..2FA1D ; Alphabetic # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D 30000..3134A ; Alphabetic # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A -31350..323AF ; Alphabetic # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF +31350..33479 ; Alphabetic # Lo [8490] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-33479 -# Total code points: 142759 +# Total code points: 147421 # ================================================ @@ -1595,7 +1620,7 @@ FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANG 024B ; Lowercase # L& LATIN SMALL LETTER Q WITH HOOK TAIL 024D ; Lowercase # L& LATIN SMALL LETTER R WITH STROKE 024F..0293 ; Lowercase # L& [69] LATIN SMALL LETTER Y WITH STROKE..LATIN SMALL LETTER EZH WITH CURL -0295..02AF ; Lowercase # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +0296..02AF ; Lowercase # L& [26] LATIN LETTER INVERTED GLOTTAL STOP..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL 02B0..02B8 ; Lowercase # Lm [9] MODIFIER LETTER SMALL H..MODIFIER LETTER SMALL Y 02C0..02C1 ; Lowercase # Lm [2] MODIFIER LETTER GLOTTAL STOP..MODIFIER LETTER REVERSED GLOTTAL STOP 02E0..02E4 ; Lowercase # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP @@ -2073,13 +2098,14 @@ A7C3 ; Lowercase # L& LATIN SMALL LETTER ANGLICANA W A7C8 ; Lowercase # L& LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY A7CA ; Lowercase # L& LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY A7CD ; Lowercase # L& LATIN SMALL LETTER S WITH DIAGONAL STROKE +A7CF ; Lowercase # L& LATIN SMALL LETTER PHARYNGEAL VOICED FRICATIVE A7D1 ; Lowercase # L& LATIN SMALL LETTER CLOSED INSULAR G A7D3 ; Lowercase # L& LATIN SMALL LETTER DOUBLE THORN A7D5 ; Lowercase # L& LATIN SMALL LETTER DOUBLE WYNN A7D7 ; Lowercase # L& LATIN SMALL LETTER MIDDLE SCOTS S A7D9 ; Lowercase # L& LATIN SMALL LETTER SIGMOID S A7DB ; Lowercase # L& LATIN SMALL LETTER LAMBDA -A7F2..A7F4 ; Lowercase # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q +A7F1..A7F4 ; Lowercase # Lm [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q A7F6 ; Lowercase # L& LATIN SMALL LETTER REVERSED HALF H A7F8..A7F9 ; Lowercase # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE A7FA ; Lowercase # L& LATIN LETTER SMALL CAPITAL TURNED M @@ -2105,6 +2131,7 @@ FF41..FF5A ; Lowercase # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 10D70..10D85 ; Lowercase # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118C0..118DF ; Lowercase # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E60..16E7F ; Lowercase # L& [32] MEDEFAIDRIN SMALL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16EBB..16ED3 ; Lowercase # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY 1D41A..1D433 ; Lowercase # L& [26] MATHEMATICAL BOLD SMALL A..MATHEMATICAL BOLD SMALL Z 1D44E..1D454 ; Lowercase # L& [7] MATHEMATICAL ITALIC SMALL A..MATHEMATICAL ITALIC SMALL G 1D456..1D467 ; Lowercase # L& [18] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL ITALIC SMALL Z @@ -2139,7 +2166,7 @@ FF41..FF5A ; Lowercase # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 1E030..1E06D ; Lowercase # Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE 1E922..1E943 ; Lowercase # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 2569 +# Total code points: 2595 # ================================================ @@ -2750,7 +2777,10 @@ A7C2 ; Uppercase # L& LATIN CAPITAL LETTER ANGLICANA W A7C4..A7C7 ; Uppercase # L& [4] LATIN CAPITAL LETTER C WITH PALATAL HOOK..LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9 ; Uppercase # L& LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY A7CB..A7CC ; Uppercase # L& [2] LATIN CAPITAL LETTER RAMS HORN..LATIN CAPITAL LETTER S WITH DIAGONAL STROKE +A7CE ; Uppercase # L& LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE A7D0 ; Uppercase # L& LATIN CAPITAL LETTER CLOSED INSULAR G +A7D2 ; Uppercase # L& LATIN CAPITAL LETTER DOUBLE THORN +A7D4 ; Uppercase # L& LATIN CAPITAL LETTER DOUBLE WYNN A7D6 ; Uppercase # L& LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8 ; Uppercase # L& LATIN CAPITAL LETTER SIGMOID S A7DA ; Uppercase # L& LATIN CAPITAL LETTER LAMBDA @@ -2767,6 +2797,7 @@ FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH 10D50..10D65 ; Uppercase # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA 118A0..118BF ; Uppercase # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 16E40..16E5F ; Uppercase # L& [32] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN CAPITAL LETTER Y +16EA0..16EB8 ; Uppercase # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY 1D400..1D419 ; Uppercase # L& [26] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL BOLD CAPITAL Z 1D434..1D44D ; Uppercase # L& [26] MATHEMATICAL ITALIC CAPITAL A..MATHEMATICAL ITALIC CAPITAL Z 1D468..1D481 ; Uppercase # L& [26] MATHEMATICAL BOLD ITALIC CAPITAL A..MATHEMATICAL BOLD ITALIC CAPITAL Z @@ -2803,7 +2834,7 @@ FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH 1F150..1F169 ; Uppercase # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F170..1F189 ; Uppercase # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 1978 +# Total code points: 2006 # ================================================ @@ -2821,7 +2852,7 @@ FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH 00F8..01BA ; Cased # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL 01BC..01BF ; Cased # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN 01C4..0293 ; Cased # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL -0295..02AF ; Cased # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +0296..02AF ; Cased # L& [26] LATIN LETTER INVERTED GLOTTAL STOP..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL 02B0..02B8 ; Cased # Lm [9] MODIFIER LETTER SMALL H..MODIFIER LETTER SMALL Y 02C0..02C1 ; Cased # Lm [2] MODIFIER LETTER GLOTTAL STOP..MODIFIER LETTER REVERSED GLOTTAL STOP 02E0..02E4 ; Cased # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP @@ -2911,11 +2942,8 @@ A722..A76F ; Cased # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN A770 ; Cased # Lm MODIFIER LETTER US A771..A787 ; Cased # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T A78B..A78E ; Cased # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT -A790..A7CD ; Cased # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE -A7D0..A7D1 ; Cased # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G -A7D3 ; Cased # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7DC ; Cased # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE -A7F2..A7F4 ; Cased # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q +A790..A7DC ; Cased # L& [77] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER LAMBDA WITH STROKE +A7F1..A7F4 ; Cased # Lm [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; Cased # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F8..A7F9 ; Cased # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE A7FA ; Cased # L& LATIN LETTER SMALL CAPITAL TURNED M @@ -2949,6 +2977,8 @@ FF41..FF5A ; Cased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 10D70..10D85 ; Cased # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118A0..118DF ; Cased # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E40..16E7F ; Cased # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16EA0..16EB8 ; Cased # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY +16EBB..16ED3 ; Cased # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY 1D400..1D454 ; Cased # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G 1D456..1D49C ; Cased # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A 1D49E..1D49F ; Cased # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D @@ -2988,7 +3018,7 @@ FF41..FF5A ; Cased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 1F150..1F169 ; Cased # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F170..1F189 ; Cased # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 4578 +# Total code points: 4632 # ================================================ @@ -3194,7 +3224,8 @@ FF41..FF5A ; Cased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 1AA7 ; Case_Ignorable # Lm TAI THAM SIGN MAI YAMOK 1AB0..1ABD ; Case_Ignorable # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW 1ABE ; Case_Ignorable # Me COMBINING PARENTHESES OVERLAY -1ABF..1ACE ; Case_Ignorable # Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T +1ABF..1ADD ; Case_Ignorable # Mn [31] COMBINING LATIN SMALL LETTER W BELOW..COMBINING DOT-AND-RING BELOW +1AE0..1AEB ; Case_Ignorable # Mn [12] COMBINING LEFT TACK ABOVE..COMBINING DOUBLE RIGHTWARDS ARROW ABOVE 1B00..1B03 ; Case_Ignorable # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG 1B34 ; Case_Ignorable # Mn BALINESE SIGN REREKAN 1B36..1B3A ; Case_Ignorable # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA @@ -3274,7 +3305,7 @@ A720..A721 ; Case_Ignorable # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE.. A770 ; Case_Ignorable # Lm MODIFIER LETTER US A788 ; Case_Ignorable # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A789..A78A ; Case_Ignorable # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN -A7F2..A7F4 ; Case_Ignorable # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q +A7F1..A7F4 ; Case_Ignorable # Lm [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q A7F8..A7F9 ; Case_Ignorable # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE A802 ; Case_Ignorable # Mn SYLOTI NAGRI SIGN DVISVARA A806 ; Case_Ignorable # Mn SYLOTI NAGRI SIGN HASANTA @@ -3350,7 +3381,8 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 10D69..10D6D ; Case_Ignorable # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK 10D6F ; Case_Ignorable # Lm GARAY REDUPLICATION MARK 10EAB..10EAC ; Case_Ignorable # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK -10EFC..10EFF ; Case_Ignorable # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA +10EC5 ; Case_Ignorable # Lm ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW +10EFA..10EFF ; Case_Ignorable # Mn [6] ARABIC DOUBLE VERTICAL BAR BELOW..ARABIC SMALL LOW WORD MADDA 10F46..10F50 ; Case_Ignorable # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW 10F82..10F85 ; Case_Ignorable # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW 11001 ; Case_Ignorable # Mn BRAHMI SIGN ANUSVARA @@ -3427,6 +3459,9 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 11A59..11A5B ; Case_Ignorable # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK 11A8A..11A96 ; Case_Ignorable # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA 11A98..11A99 ; Case_Ignorable # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11B60 ; Case_Ignorable # Mn SHARADA VOWEL SIGN OE +11B62..11B64 ; Case_Ignorable # Mn [3] SHARADA VOWEL SIGN UE..SHARADA VOWEL SIGN SHORT E +11B66 ; Case_Ignorable # Mn SHARADA VOWEL SIGN CANDRA E 11C30..11C36 ; Case_Ignorable # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L 11C38..11C3D ; Case_Ignorable # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA 11C3F ; Case_Ignorable # Mn BHAIKSUKI SIGN VIRAMA @@ -3442,6 +3477,7 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 11D90..11D91 ; Case_Ignorable # Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI 11D95 ; Case_Ignorable # Mn GUNJALA GONDI SIGN ANUSVARA 11D97 ; Case_Ignorable # Mn GUNJALA GONDI VIRAMA +11DD9 ; Case_Ignorable # Lm TOLONG SIKI SIGN SELA 11EF3..11EF4 ; Case_Ignorable # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U 11F00..11F01 ; Case_Ignorable # Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA 11F36..11F3A ; Case_Ignorable # Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R @@ -3464,6 +3500,7 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 16FE0..16FE1 ; Case_Ignorable # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK 16FE3 ; Case_Ignorable # Lm OLD CHINESE ITERATION MARK 16FE4 ; Case_Ignorable # Mn KHITAN SMALL SCRIPT FILLER +16FF2..16FF3 ; Case_Ignorable # Lm [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER 1AFF0..1AFF3 ; Case_Ignorable # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; Case_Ignorable # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; Case_Ignorable # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -3497,6 +3534,11 @@ FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLI 1E4EB ; Case_Ignorable # Lm NAG MUNDARI SIGN OJOD 1E4EC..1E4EF ; Case_Ignorable # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH 1E5EE..1E5EF ; Case_Ignorable # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR +1E6E3 ; Case_Ignorable # Mn TAI YO SIGN UE +1E6E6 ; Case_Ignorable # Mn TAI YO SIGN AU +1E6EE..1E6EF ; Case_Ignorable # Mn [2] TAI YO SIGN AY..TAI YO SIGN ANG +1E6F5 ; Case_Ignorable # Mn TAI YO SIGN OM +1E6FF ; Case_Ignorable # Lm TAI YO XAM LAI 1E8D0..1E8D6 ; Case_Ignorable # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS 1E944..1E94A ; Case_Ignorable # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA 1E94B ; Case_Ignorable # Lm ADLAM NASALIZATION MARK @@ -3505,13 +3547,14 @@ E0001 ; Case_Ignorable # Cf LANGUAGE TAG E0020..E007F ; Case_Ignorable # Cf [96] TAG SPACE..CANCEL TAG E0100..E01EF ; Case_Ignorable # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 2749 +# Total code points: 2794 # ================================================ # Derived Property: Changes_When_Lowercased (CWL) # Characters whose normalized forms are not stable under a toLowercase mapping. -# For more information, see D139 in Section 3.13, "Default Case Algorithms". +# For more information, see the definition of "isLowercase(X)" +# in the "Conformance" / "Default Case Algorithms" section of the core specification. # Changes_When_Lowercased(X) is true when toLowercase(toNFD(X)) != toNFD(X) 0041..005A ; Changes_When_Lowercased # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z @@ -4110,7 +4153,10 @@ A7C2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER ANGLICAN A7C4..A7C7 ; Changes_When_Lowercased # L& [4] LATIN CAPITAL LETTER C WITH PALATAL HOOK..LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY A7CB..A7CC ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER RAMS HORN..LATIN CAPITAL LETTER S WITH DIAGONAL STROKE +A7CE ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE A7D0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER CLOSED INSULAR G +A7D2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER DOUBLE THORN +A7D4 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER DOUBLE WYNN A7D6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER SIGMOID S A7DA ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER LAMBDA @@ -4127,15 +4173,17 @@ FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTE 10D50..10D65 ; Changes_When_Lowercased # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA 118A0..118BF ; Changes_When_Lowercased # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 16E40..16E5F ; Changes_When_Lowercased # L& [32] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN CAPITAL LETTER Y +16EA0..16EB8 ; Changes_When_Lowercased # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY 1E900..1E921 ; Changes_When_Lowercased # L& [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA -# Total code points: 1460 +# Total code points: 1488 # ================================================ # Derived Property: Changes_When_Uppercased (CWU) # Characters whose normalized forms are not stable under a toUppercase mapping. -# For more information, see D140 in Section 3.13, "Default Case Algorithms". +# For more information, see the definition of "isUppercase(X)" +# in the "Conformance" / "Default Case Algorithms" section of the core specification. # Changes_When_Uppercased(X) is true when toUppercase(toNFD(X)) != toNFD(X) 0061..007A ; Changes_When_Uppercased # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z @@ -4747,7 +4795,10 @@ A7C3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER ANGLICANA A7C8 ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY A7CA ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY A7CD ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH DIAGONAL STROKE +A7CF ; Changes_When_Uppercased # L& LATIN SMALL LETTER PHARYNGEAL VOICED FRICATIVE A7D1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER CLOSED INSULAR G +A7D3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER DOUBLE THORN +A7D5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER DOUBLE WYNN A7D7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER MIDDLE SCOTS S A7D9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER SIGMOID S A7DB ; Changes_When_Uppercased # L& LATIN SMALL LETTER LAMBDA @@ -4767,15 +4818,17 @@ FF41..FF5A ; Changes_When_Uppercased # L& [26] FULLWIDTH LATIN SMALL LETTER 10D70..10D85 ; Changes_When_Uppercased # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118C0..118DF ; Changes_When_Uppercased # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E60..16E7F ; Changes_When_Uppercased # L& [32] MEDEFAIDRIN SMALL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16EBB..16ED3 ; Changes_When_Uppercased # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY 1E922..1E943 ; Changes_When_Uppercased # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 1552 +# Total code points: 1580 # ================================================ # Derived Property: Changes_When_Titlecased (CWT) # Characters whose normalized forms are not stable under a toTitlecase mapping. -# For more information, see D141 in Section 3.13, "Default Case Algorithms". +# For more information, see the definition of "isTitlecase(X)" +# in the "Conformance" / "Default Case Algorithms" section of the core specification. # Changes_When_Titlecased(X) is true when toTitlecase(toNFD(X)) != toNFD(X) 0061..007A ; Changes_When_Titlecased # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z @@ -5386,7 +5439,10 @@ A7C3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER ANGLICANA A7C8 ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY A7CA ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY A7CD ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH DIAGONAL STROKE +A7CF ; Changes_When_Titlecased # L& LATIN SMALL LETTER PHARYNGEAL VOICED FRICATIVE A7D1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER CLOSED INSULAR G +A7D3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER DOUBLE THORN +A7D5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER DOUBLE WYNN A7D7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER MIDDLE SCOTS S A7D9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER SIGMOID S A7DB ; Changes_When_Titlecased # L& LATIN SMALL LETTER LAMBDA @@ -5406,15 +5462,17 @@ FF41..FF5A ; Changes_When_Titlecased # L& [26] FULLWIDTH LATIN SMALL LETTER 10D70..10D85 ; Changes_When_Titlecased # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118C0..118DF ; Changes_When_Titlecased # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E60..16E7F ; Changes_When_Titlecased # L& [32] MEDEFAIDRIN SMALL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16EBB..16ED3 ; Changes_When_Titlecased # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY 1E922..1E943 ; Changes_When_Titlecased # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 1479 +# Total code points: 1507 # ================================================ # Derived Property: Changes_When_Casefolded (CWCF) # Characters whose normalized forms are not stable under case folding. -# For more information, see D142 in Section 3.13, "Default Case Algorithms". +# For more information, see the definition of "isCasefolded(X)" +# in the "Conformance" / "Default Case Algorithms" section of the core specification. # Changes_When_Casefolded(X) is true when toCasefold(toNFD(X)) != toNFD(X) 0041..005A ; Changes_When_Casefolded # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z @@ -6022,7 +6080,10 @@ A7C2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER ANGLICAN A7C4..A7C7 ; Changes_When_Casefolded # L& [4] LATIN CAPITAL LETTER C WITH PALATAL HOOK..LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY A7CB..A7CC ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER RAMS HORN..LATIN CAPITAL LETTER S WITH DIAGONAL STROKE +A7CE ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE A7D0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER CLOSED INSULAR G +A7D2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER DOUBLE THORN +A7D4 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER DOUBLE WYNN A7D6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER MIDDLE SCOTS S A7D8 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER SIGMOID S A7DA ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER LAMBDA @@ -6042,15 +6103,17 @@ FF21..FF3A ; Changes_When_Casefolded # L& [26] FULLWIDTH LATIN CAPITAL LETTE 10D50..10D65 ; Changes_When_Casefolded # L& [22] GARAY CAPITAL LETTER A..GARAY CAPITAL LETTER OLD NA 118A0..118BF ; Changes_When_Casefolded # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 16E40..16E5F ; Changes_When_Casefolded # L& [32] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN CAPITAL LETTER Y +16EA0..16EB8 ; Changes_When_Casefolded # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY 1E900..1E921 ; Changes_When_Casefolded # L& [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA -# Total code points: 1533 +# Total code points: 1561 # ================================================ # Derived Property: Changes_When_Casemapped (CWCM) # Characters whose normalized forms are not stable under case mapping. -# For more information, see D143 in Section 3.13, "Default Case Algorithms". +# For more information, see the definition of "isCased(X)" +# in the "Conformance" / "Default Case Algorithms" section of the core specification. # Changes_When_Casemapped(X) is true when CWL(X), or CWT(X), or CWU(X) 0041..005A ; Changes_When_Casemapped # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z @@ -6156,9 +6219,7 @@ A779..A787 ; Changes_When_Casemapped # L& [15] LATIN CAPITAL LETTER INSULAR A78B..A78D ; Changes_When_Casemapped # L& [3] LATIN CAPITAL LETTER SALTILLO..LATIN CAPITAL LETTER TURNED H A790..A794 ; Changes_When_Casemapped # L& [5] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER C WITH PALATAL HOOK A796..A7AE ; Changes_When_Casemapped # L& [25] LATIN CAPITAL LETTER B WITH FLOURISH..LATIN CAPITAL LETTER SMALL CAPITAL I -A7B0..A7CD ; Changes_When_Casemapped # L& [30] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER S WITH DIAGONAL STROKE -A7D0..A7D1 ; Changes_When_Casemapped # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G -A7D6..A7DC ; Changes_When_Casemapped # L& [7] LATIN CAPITAL LETTER MIDDLE SCOTS S..LATIN CAPITAL LETTER LAMBDA WITH STROKE +A7B0..A7DC ; Changes_When_Casemapped # L& [45] LATIN CAPITAL LETTER TURNED K..LATIN CAPITAL LETTER LAMBDA WITH STROKE A7F5..A7F6 ; Changes_When_Casemapped # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H AB53 ; Changes_When_Casemapped # L& LATIN SMALL LETTER CHI AB70..ABBF ; Changes_When_Casemapped # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA @@ -6183,9 +6244,11 @@ FF41..FF5A ; Changes_When_Casemapped # L& [26] FULLWIDTH LATIN SMALL LETTER 10D70..10D85 ; Changes_When_Casemapped # L& [22] GARAY SMALL LETTER A..GARAY SMALL LETTER OLD NA 118A0..118DF ; Changes_When_Casemapped # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 16E40..16E7F ; Changes_When_Casemapped # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16EA0..16EB8 ; Changes_When_Casemapped # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY +16EBB..16ED3 ; Changes_When_Casemapped # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY 1E900..1E943 ; Changes_When_Casemapped # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 2981 +# Total code points: 3037 # ================================================ @@ -6210,8 +6273,8 @@ FF41..FF5A ; Changes_When_Casemapped # L& [26] FULLWIDTH LATIN SMALL LETTER 01BC..01BF ; ID_Start # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN 01C0..01C3 ; ID_Start # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK 01C4..0293 ; ID_Start # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL -0294 ; ID_Start # Lo LATIN LETTER GLOTTAL STOP -0295..02AF ; ID_Start # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +0294..0295 ; ID_Start # Lo [2] LATIN LETTER GLOTTAL STOP..LATIN LETTER PHARYNGEAL VOICED FRICATIVE +0296..02AF ; ID_Start # L& [26] LATIN LETTER INVERTED GLOTTAL STOP..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL 02B0..02C1 ; ID_Start # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP 02C6..02D1 ; ID_Start # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON 02E0..02E4 ; ID_Start # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP @@ -6259,7 +6322,7 @@ FF41..FF5A ; Changes_When_Casemapped # L& [26] FULLWIDTH LATIN SMALL LETTER 0840..0858 ; ID_Start # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN 0860..086A ; ID_Start # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 0870..0887 ; ID_Start # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT -0889..088E ; ID_Start # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL +0889..088F ; ID_Start # Lo [7] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC LETTER NOON WITH RING ABOVE 08A0..08C8 ; ID_Start # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; ID_Start # Lm ARABIC SMALL FARSI YEH 0904..0939 ; ID_Start # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA @@ -6327,7 +6390,7 @@ FF41..FF5A ; Changes_When_Casemapped # L& [26] FULLWIDTH LATIN SMALL LETTER 0C2A..0C39 ; ID_Start # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA 0C3D ; ID_Start # Lo TELUGU SIGN AVAGRAHA 0C58..0C5A ; ID_Start # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA -0C5D ; ID_Start # Lo TELUGU LETTER NAKAARA POLLU +0C5C..0C5D ; ID_Start # Lo [2] TELUGU ARCHAIC SHRII..TELUGU LETTER NAKAARA POLLU 0C60..0C61 ; ID_Start # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL 0C80 ; ID_Start # Lo KANNADA SIGN SPACING CANDRABINDU 0C85..0C8C ; ID_Start # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L @@ -6336,7 +6399,7 @@ FF41..FF5A ; Changes_When_Casemapped # L& [26] FULLWIDTH LATIN SMALL LETTER 0CAA..0CB3 ; ID_Start # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA 0CB5..0CB9 ; ID_Start # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA 0CBD ; ID_Start # Lo KANNADA SIGN AVAGRAHA -0CDD..0CDE ; ID_Start # Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA +0CDC..0CDE ; ID_Start # Lo [3] KANNADA ARCHAIC SHRII..KANNADA LETTER FA 0CE0..0CE1 ; ID_Start # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL 0CF1..0CF2 ; ID_Start # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA 0D04..0D0C ; ID_Start # Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L @@ -6561,11 +6624,8 @@ A771..A787 ; ID_Start # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER I A788 ; ID_Start # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; ID_Start # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; ID_Start # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CD ; ID_Start # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE -A7D0..A7D1 ; ID_Start # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G -A7D3 ; ID_Start # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7DC ; ID_Start # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE -A7F2..A7F4 ; ID_Start # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q +A790..A7DC ; ID_Start # L& [77] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER LAMBDA WITH STROKE +A7F1..A7F4 ; ID_Start # Lm [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; ID_Start # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; ID_Start # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; ID_Start # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -6702,6 +6762,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 108F4..108F5 ; ID_Start # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW 10900..10915 ; ID_Start # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU 10920..10939 ; ID_Start # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C +10940..10959 ; ID_Start # Lo [26] SIDETIC LETTER N01..SIDETIC LETTER N26 10980..109B7 ; ID_Start # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA 109BE..109BF ; ID_Start # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN 10A00 ; ID_Start # Lo KHAROSHTHI LETTER A @@ -6729,6 +6790,8 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 10E80..10EA9 ; ID_Start # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EB0..10EB1 ; ID_Start # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE 10EC2..10EC4 ; ID_Start # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW +10EC5 ; ID_Start # Lm ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW +10EC6..10EC7 ; ID_Start # Lo [2] ARABIC LETTER THIN NOON..ARABIC LETTER YEH WITH FOUR DOTS BELOW 10F00..10F1C ; ID_Start # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; ID_Start # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; ID_Start # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -6821,6 +6884,9 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 11D67..11D68 ; ID_Start # Lo [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI 11D6A..11D89 ; ID_Start # Lo [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA 11D98 ; ID_Start # Lo GUNJALA GONDI OM +11DB0..11DD8 ; ID_Start # Lo [41] TOLONG SIKI LETTER I..TOLONG SIKI LETTER RRH +11DD9 ; ID_Start # Lm TOLONG SIKI SIGN SELA +11DDA..11DDB ; ID_Start # Lo [2] TOLONG SIKI SIGN HECAKA..TOLONG SIKI UNGGA 11EE0..11EF2 ; ID_Start # Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA 11F02 ; ID_Start # Lo KAWI SIGN REPHA 11F04..11F10 ; ID_Start # Lo [13] KAWI LETTER A..KAWI LETTER O @@ -6847,14 +6913,18 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 16D43..16D6A ; ID_Start # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU 16D6B..16D6C ; ID_Start # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16E40..16E7F ; ID_Start # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16EA0..16EB8 ; ID_Start # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY +16EBB..16ED3 ; ID_Start # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY 16F00..16F4A ; ID_Start # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F50 ; ID_Start # Lo MIAO LETTER NASALIZATION 16F93..16F9F ; ID_Start # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 16FE0..16FE1 ; ID_Start # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK 16FE3 ; ID_Start # Lm OLD CHINESE ITERATION MARK -17000..187F7 ; ID_Start # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 -18800..18CD5 ; ID_Start # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18CFF..18D08 ; ID_Start # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 +16FF2..16FF3 ; ID_Start # Lm [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER +16FF4..16FF6 ; ID_Start # Nl [3] YANGQIN SIGN SLOW ONE BEAT..YANGQIN SIGN SLOW TWO BEATS +17000..18CD5 ; ID_Start # Lo [7382] TANGUT IDEOGRAPH-17000..KHITAN SMALL SCRIPT CHARACTER-18CD5 +18CFF..18D1E ; ID_Start # Lo [32] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D1E +18D80..18DF2 ; ID_Start # Lo [115] TANGUT COMPONENT-769..TANGUT COMPONENT-883 1AFF0..1AFF3 ; ID_Start # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; ID_Start # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; ID_Start # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -6912,6 +6982,13 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1E4EB ; ID_Start # Lm NAG MUNDARI SIGN OJOD 1E5D0..1E5ED ; ID_Start # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG 1E5F0 ; ID_Start # Lo OL ONAL SIGN HODDOND +1E6C0..1E6DE ; ID_Start # Lo [31] TAI YO LETTER LOW KO..TAI YO LETTER HIGH KVO +1E6E0..1E6E2 ; ID_Start # Lo [3] TAI YO LETTER AA..TAI YO LETTER UE +1E6E4..1E6E5 ; ID_Start # Lo [2] TAI YO LETTER U..TAI YO LETTER AE +1E6E7..1E6ED ; ID_Start # Lo [7] TAI YO LETTER O..TAI YO LETTER AUE +1E6F0..1E6F4 ; ID_Start # Lo [5] TAI YO LETTER AN..TAI YO LETTER AP +1E6FE ; ID_Start # Lo TAI YO SYMBOL MUEANG +1E6FF ; ID_Start # Lm TAI YO XAM LAI 1E7E0..1E7E6 ; ID_Start # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; ID_Start # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; ID_Start # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -6953,16 +7030,15 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1EEA5..1EEA9 ; ID_Start # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH 1EEAB..1EEBB ; ID_Start # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 20000..2A6DF ; ID_Start # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF -2A700..2B739 ; ID_Start # Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 -2B740..2B81D ; ID_Start # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D -2B820..2CEA1 ; ID_Start # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2A700..2B81D ; ID_Start # Lo [4382] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B81D +2B820..2CEAD ; ID_Start # Lo [5774] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEAD 2CEB0..2EBE0 ; ID_Start # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 2EBF0..2EE5D ; ID_Start # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D 2F800..2FA1D ; ID_Start # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D 30000..3134A ; ID_Start # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A -31350..323AF ; ID_Start # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF +31350..33479 ; ID_Start # Lo [8490] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-33479 -# Total code points: 141269 +# Total code points: 145916 # ================================================ @@ -6991,8 +7067,8 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 01BC..01BF ; ID_Continue # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN 01C0..01C3 ; ID_Continue # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK 01C4..0293 ; ID_Continue # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL -0294 ; ID_Continue # Lo LATIN LETTER GLOTTAL STOP -0295..02AF ; ID_Continue # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +0294..0295 ; ID_Continue # Lo [2] LATIN LETTER GLOTTAL STOP..LATIN LETTER PHARYNGEAL VOICED FRICATIVE +0296..02AF ; ID_Continue # L& [26] LATIN LETTER INVERTED GLOTTAL STOP..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL 02B0..02C1 ; ID_Continue # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP 02C6..02D1 ; ID_Continue # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON 02E0..02E4 ; ID_Continue # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP @@ -7068,7 +7144,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 0859..085B ; ID_Continue # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK 0860..086A ; ID_Continue # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 0870..0887 ; ID_Continue # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT -0889..088E ; ID_Continue # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL +0889..088F ; ID_Continue # Lo [7] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC LETTER NOON WITH RING ABOVE 0897..089F ; ID_Continue # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08A0..08C8 ; ID_Continue # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; ID_Continue # Lm ARABIC SMALL FARSI YEH @@ -7218,7 +7294,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 0C4A..0C4D ; ID_Continue # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA 0C55..0C56 ; ID_Continue # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK 0C58..0C5A ; ID_Continue # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA -0C5D ; ID_Continue # Lo TELUGU LETTER NAKAARA POLLU +0C5C..0C5D ; ID_Continue # Lo [2] TELUGU ARCHAIC SHRII..TELUGU LETTER NAKAARA POLLU 0C60..0C61 ; ID_Continue # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL 0C62..0C63 ; ID_Continue # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL 0C66..0C6F ; ID_Continue # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE @@ -7240,7 +7316,7 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 0CCA..0CCB ; ID_Continue # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO 0CCC..0CCD ; ID_Continue # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA 0CD5..0CD6 ; ID_Continue # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK -0CDD..0CDE ; ID_Continue # Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA +0CDC..0CDE ; ID_Continue # Lo [3] KANNADA ARCHAIC SHRII..KANNADA LETTER FA 0CE0..0CE1 ; ID_Continue # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL 0CE2..0CE3 ; ID_Continue # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL 0CE6..0CEF ; ID_Continue # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE @@ -7457,7 +7533,8 @@ FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1A90..1A99 ; ID_Continue # Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE 1AA7 ; ID_Continue # Lm TAI THAM SIGN MAI YAMOK 1AB0..1ABD ; ID_Continue # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW -1ABF..1ACE ; ID_Continue # Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T +1ABF..1ADD ; ID_Continue # Mn [31] COMBINING LATIN SMALL LETTER W BELOW..COMBINING DOT-AND-RING BELOW +1AE0..1AEB ; ID_Continue # Mn [12] COMBINING LEFT TACK ABOVE..COMBINING DOUBLE RIGHTWARDS ARROW ABOVE 1B00..1B03 ; ID_Continue # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG 1B04 ; ID_Continue # Mc BALINESE SIGN BISAH 1B05..1B33 ; ID_Continue # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA @@ -7646,11 +7723,8 @@ A771..A787 ; ID_Continue # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTE A788 ; ID_Continue # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; ID_Continue # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; ID_Continue # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CD ; ID_Continue # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE -A7D0..A7D1 ; ID_Continue # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G -A7D3 ; ID_Continue # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7DC ; ID_Continue # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE -A7F2..A7F4 ; ID_Continue # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q +A790..A7DC ; ID_Continue # L& [77] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER LAMBDA WITH STROKE +A7F1..A7F4 ; ID_Continue # Lm [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; ID_Continue # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; ID_Continue # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; ID_Continue # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -7857,6 +7931,7 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 108F4..108F5 ; ID_Continue # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW 10900..10915 ; ID_Continue # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU 10920..10939 ; ID_Continue # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C +10940..10959 ; ID_Continue # Lo [26] SIDETIC LETTER N01..SIDETIC LETTER N26 10980..109B7 ; ID_Continue # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA 109BE..109BF ; ID_Continue # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN 10A00 ; ID_Continue # Lo KHAROSHTHI LETTER A @@ -7895,7 +7970,9 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 10EAB..10EAC ; ID_Continue # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK 10EB0..10EB1 ; ID_Continue # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE 10EC2..10EC4 ; ID_Continue # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW -10EFC..10EFF ; ID_Continue # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA +10EC5 ; ID_Continue # Lm ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW +10EC6..10EC7 ; ID_Continue # Lo [2] ARABIC LETTER THIN NOON..ARABIC LETTER YEH WITH FOUR DOTS BELOW +10EFA..10EFF ; ID_Continue # Mn [6] ARABIC DOUBLE VERTICAL BAR BELOW..ARABIC SMALL LOW WORD MADDA 10F00..10F1C ; ID_Continue # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; ID_Continue # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; ID_Continue # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -8122,6 +8199,12 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 11A98..11A99 ; ID_Continue # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER 11A9D ; ID_Continue # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; ID_Continue # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11B60 ; ID_Continue # Mn SHARADA VOWEL SIGN OE +11B61 ; ID_Continue # Mc SHARADA VOWEL SIGN OOE +11B62..11B64 ; ID_Continue # Mn [3] SHARADA VOWEL SIGN UE..SHARADA VOWEL SIGN SHORT E +11B65 ; ID_Continue # Mc SHARADA VOWEL SIGN SHORT O +11B66 ; ID_Continue # Mn SHARADA VOWEL SIGN CANDRA E +11B67 ; ID_Continue # Mc SHARADA VOWEL SIGN CANDRA O 11BC0..11BE0 ; ID_Continue # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO 11BF0..11BF9 ; ID_Continue # Nd [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE 11C00..11C08 ; ID_Continue # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L @@ -8162,6 +8245,10 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 11D97 ; ID_Continue # Mn GUNJALA GONDI VIRAMA 11D98 ; ID_Continue # Lo GUNJALA GONDI OM 11DA0..11DA9 ; ID_Continue # Nd [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE +11DB0..11DD8 ; ID_Continue # Lo [41] TOLONG SIKI LETTER I..TOLONG SIKI LETTER RRH +11DD9 ; ID_Continue # Lm TOLONG SIKI SIGN SELA +11DDA..11DDB ; ID_Continue # Lo [2] TOLONG SIKI SIGN HECAKA..TOLONG SIKI UNGGA +11DE0..11DE9 ; ID_Continue # Nd [10] TOLONG SIKI DIGIT ZERO..TOLONG SIKI DIGIT NINE 11EE0..11EF2 ; ID_Continue # Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA 11EF3..11EF4 ; ID_Continue # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U 11EF5..11EF6 ; ID_Continue # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O @@ -8212,6 +8299,8 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 16D6B..16D6C ; ID_Continue # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16D70..16D79 ; ID_Continue # Nd [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE 16E40..16E7F ; ID_Continue # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16EA0..16EB8 ; ID_Continue # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY +16EBB..16ED3 ; ID_Continue # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY 16F00..16F4A ; ID_Continue # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F4F ; ID_Continue # Mn MIAO SIGN CONSONANT MODIFIER BAR 16F50 ; ID_Continue # Lo MIAO LETTER NASALIZATION @@ -8222,9 +8311,11 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 16FE3 ; ID_Continue # Lm OLD CHINESE ITERATION MARK 16FE4 ; ID_Continue # Mn KHITAN SMALL SCRIPT FILLER 16FF0..16FF1 ; ID_Continue # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY -17000..187F7 ; ID_Continue # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 -18800..18CD5 ; ID_Continue # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18CFF..18D08 ; ID_Continue # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 +16FF2..16FF3 ; ID_Continue # Lm [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER +16FF4..16FF6 ; ID_Continue # Nl [3] YANGQIN SIGN SLOW ONE BEAT..YANGQIN SIGN SLOW TWO BEATS +17000..18CD5 ; ID_Continue # Lo [7382] TANGUT IDEOGRAPH-17000..KHITAN SMALL SCRIPT CHARACTER-18CD5 +18CFF..18D1E ; ID_Continue # Lo [32] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D1E +18D80..18DF2 ; ID_Continue # Lo [115] TANGUT COMPONENT-769..TANGUT COMPONENT-883 1AFF0..1AFF3 ; ID_Continue # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; ID_Continue # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; ID_Continue # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -8315,6 +8406,17 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 1E5EE..1E5EF ; ID_Continue # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR 1E5F0 ; ID_Continue # Lo OL ONAL SIGN HODDOND 1E5F1..1E5FA ; ID_Continue # Nd [10] OL ONAL DIGIT ZERO..OL ONAL DIGIT NINE +1E6C0..1E6DE ; ID_Continue # Lo [31] TAI YO LETTER LOW KO..TAI YO LETTER HIGH KVO +1E6E0..1E6E2 ; ID_Continue # Lo [3] TAI YO LETTER AA..TAI YO LETTER UE +1E6E3 ; ID_Continue # Mn TAI YO SIGN UE +1E6E4..1E6E5 ; ID_Continue # Lo [2] TAI YO LETTER U..TAI YO LETTER AE +1E6E6 ; ID_Continue # Mn TAI YO SIGN AU +1E6E7..1E6ED ; ID_Continue # Lo [7] TAI YO LETTER O..TAI YO LETTER AUE +1E6EE..1E6EF ; ID_Continue # Mn [2] TAI YO SIGN AY..TAI YO SIGN ANG +1E6F0..1E6F4 ; ID_Continue # Lo [5] TAI YO LETTER AN..TAI YO LETTER AP +1E6F5 ; ID_Continue # Mn TAI YO SIGN OM +1E6FE ; ID_Continue # Lo TAI YO SYMBOL MUEANG +1E6FF ; ID_Continue # Lm TAI YO XAM LAI 1E7E0..1E7E6 ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; ID_Continue # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; ID_Continue # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -8360,17 +8462,16 @@ FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HAN 1EEAB..1EEBB ; ID_Continue # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 1FBF0..1FBF9 ; ID_Continue # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE 20000..2A6DF ; ID_Continue # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF -2A700..2B739 ; ID_Continue # Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 -2B740..2B81D ; ID_Continue # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D -2B820..2CEA1 ; ID_Continue # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2A700..2B81D ; ID_Continue # Lo [4382] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B81D +2B820..2CEAD ; ID_Continue # Lo [5774] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEAD 2CEB0..2EBE0 ; ID_Continue # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 2EBF0..2EE5D ; ID_Continue # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D 2F800..2FA1D ; ID_Continue # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D 30000..3134A ; ID_Continue # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A -31350..323AF ; ID_Continue # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF +31350..33479 ; ID_Continue # Lo [8490] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-33479 E0100..E01EF ; ID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 144541 +# Total code points: 149240 # ================================================ @@ -8393,8 +8494,8 @@ E0100..E01EF ; ID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR 01BC..01BF ; XID_Start # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN 01C0..01C3 ; XID_Start # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK 01C4..0293 ; XID_Start # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL -0294 ; XID_Start # Lo LATIN LETTER GLOTTAL STOP -0295..02AF ; XID_Start # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +0294..0295 ; XID_Start # Lo [2] LATIN LETTER GLOTTAL STOP..LATIN LETTER PHARYNGEAL VOICED FRICATIVE +0296..02AF ; XID_Start # L& [26] LATIN LETTER INVERTED GLOTTAL STOP..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL 02B0..02C1 ; XID_Start # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP 02C6..02D1 ; XID_Start # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON 02E0..02E4 ; XID_Start # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP @@ -8441,7 +8542,7 @@ E0100..E01EF ; ID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR 0840..0858 ; XID_Start # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN 0860..086A ; XID_Start # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 0870..0887 ; XID_Start # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT -0889..088E ; XID_Start # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL +0889..088F ; XID_Start # Lo [7] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC LETTER NOON WITH RING ABOVE 08A0..08C8 ; XID_Start # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; XID_Start # Lm ARABIC SMALL FARSI YEH 0904..0939 ; XID_Start # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA @@ -8509,7 +8610,7 @@ E0100..E01EF ; ID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR 0C2A..0C39 ; XID_Start # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA 0C3D ; XID_Start # Lo TELUGU SIGN AVAGRAHA 0C58..0C5A ; XID_Start # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA -0C5D ; XID_Start # Lo TELUGU LETTER NAKAARA POLLU +0C5C..0C5D ; XID_Start # Lo [2] TELUGU ARCHAIC SHRII..TELUGU LETTER NAKAARA POLLU 0C60..0C61 ; XID_Start # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL 0C80 ; XID_Start # Lo KANNADA SIGN SPACING CANDRABINDU 0C85..0C8C ; XID_Start # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L @@ -8518,7 +8619,7 @@ E0100..E01EF ; ID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR 0CAA..0CB3 ; XID_Start # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA 0CB5..0CB9 ; XID_Start # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA 0CBD ; XID_Start # Lo KANNADA SIGN AVAGRAHA -0CDD..0CDE ; XID_Start # Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA +0CDC..0CDE ; XID_Start # Lo [3] KANNADA ARCHAIC SHRII..KANNADA LETTER FA 0CE0..0CE1 ; XID_Start # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL 0CF1..0CF2 ; XID_Start # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA 0D04..0D0C ; XID_Start # Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L @@ -8742,11 +8843,8 @@ A771..A787 ; XID_Start # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER A788 ; XID_Start # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; XID_Start # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; XID_Start # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CD ; XID_Start # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE -A7D0..A7D1 ; XID_Start # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G -A7D3 ; XID_Start # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7DC ; XID_Start # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE -A7F2..A7F4 ; XID_Start # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q +A790..A7DC ; XID_Start # L& [77] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER LAMBDA WITH STROKE +A7F1..A7F4 ; XID_Start # Lm [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; XID_Start # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; XID_Start # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; XID_Start # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -8888,6 +8986,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 108F4..108F5 ; XID_Start # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW 10900..10915 ; XID_Start # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU 10920..10939 ; XID_Start # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C +10940..10959 ; XID_Start # Lo [26] SIDETIC LETTER N01..SIDETIC LETTER N26 10980..109B7 ; XID_Start # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA 109BE..109BF ; XID_Start # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN 10A00 ; XID_Start # Lo KHAROSHTHI LETTER A @@ -8915,6 +9014,8 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 10E80..10EA9 ; XID_Start # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET 10EB0..10EB1 ; XID_Start # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE 10EC2..10EC4 ; XID_Start # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW +10EC5 ; XID_Start # Lm ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW +10EC6..10EC7 ; XID_Start # Lo [2] ARABIC LETTER THIN NOON..ARABIC LETTER YEH WITH FOUR DOTS BELOW 10F00..10F1C ; XID_Start # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; XID_Start # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; XID_Start # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -9007,6 +9108,9 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 11D67..11D68 ; XID_Start # Lo [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI 11D6A..11D89 ; XID_Start # Lo [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA 11D98 ; XID_Start # Lo GUNJALA GONDI OM +11DB0..11DD8 ; XID_Start # Lo [41] TOLONG SIKI LETTER I..TOLONG SIKI LETTER RRH +11DD9 ; XID_Start # Lm TOLONG SIKI SIGN SELA +11DDA..11DDB ; XID_Start # Lo [2] TOLONG SIKI SIGN HECAKA..TOLONG SIKI UNGGA 11EE0..11EF2 ; XID_Start # Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA 11F02 ; XID_Start # Lo KAWI SIGN REPHA 11F04..11F10 ; XID_Start # Lo [13] KAWI LETTER A..KAWI LETTER O @@ -9033,14 +9137,18 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 16D43..16D6A ; XID_Start # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU 16D6B..16D6C ; XID_Start # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16E40..16E7F ; XID_Start # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16EA0..16EB8 ; XID_Start # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY +16EBB..16ED3 ; XID_Start # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY 16F00..16F4A ; XID_Start # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F50 ; XID_Start # Lo MIAO LETTER NASALIZATION 16F93..16F9F ; XID_Start # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 16FE0..16FE1 ; XID_Start # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK 16FE3 ; XID_Start # Lm OLD CHINESE ITERATION MARK -17000..187F7 ; XID_Start # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 -18800..18CD5 ; XID_Start # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18CFF..18D08 ; XID_Start # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 +16FF2..16FF3 ; XID_Start # Lm [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER +16FF4..16FF6 ; XID_Start # Nl [3] YANGQIN SIGN SLOW ONE BEAT..YANGQIN SIGN SLOW TWO BEATS +17000..18CD5 ; XID_Start # Lo [7382] TANGUT IDEOGRAPH-17000..KHITAN SMALL SCRIPT CHARACTER-18CD5 +18CFF..18D1E ; XID_Start # Lo [32] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D1E +18D80..18DF2 ; XID_Start # Lo [115] TANGUT COMPONENT-769..TANGUT COMPONENT-883 1AFF0..1AFF3 ; XID_Start # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; XID_Start # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; XID_Start # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -9098,6 +9206,13 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 1E4EB ; XID_Start # Lm NAG MUNDARI SIGN OJOD 1E5D0..1E5ED ; XID_Start # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG 1E5F0 ; XID_Start # Lo OL ONAL SIGN HODDOND +1E6C0..1E6DE ; XID_Start # Lo [31] TAI YO LETTER LOW KO..TAI YO LETTER HIGH KVO +1E6E0..1E6E2 ; XID_Start # Lo [3] TAI YO LETTER AA..TAI YO LETTER UE +1E6E4..1E6E5 ; XID_Start # Lo [2] TAI YO LETTER U..TAI YO LETTER AE +1E6E7..1E6ED ; XID_Start # Lo [7] TAI YO LETTER O..TAI YO LETTER AUE +1E6F0..1E6F4 ; XID_Start # Lo [5] TAI YO LETTER AN..TAI YO LETTER AP +1E6FE ; XID_Start # Lo TAI YO SYMBOL MUEANG +1E6FF ; XID_Start # Lm TAI YO XAM LAI 1E7E0..1E7E6 ; XID_Start # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; XID_Start # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; XID_Start # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -9139,16 +9254,15 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 1EEA5..1EEA9 ; XID_Start # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH 1EEAB..1EEBB ; XID_Start # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 20000..2A6DF ; XID_Start # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF -2A700..2B739 ; XID_Start # Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 -2B740..2B81D ; XID_Start # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D -2B820..2CEA1 ; XID_Start # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2A700..2B81D ; XID_Start # Lo [4382] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B81D +2B820..2CEAD ; XID_Start # Lo [5774] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEAD 2CEB0..2EBE0 ; XID_Start # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 2EBF0..2EE5D ; XID_Start # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D 2F800..2FA1D ; XID_Start # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D 30000..3134A ; XID_Start # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A -31350..323AF ; XID_Start # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF +31350..33479 ; XID_Start # Lo [8490] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-33479 -# Total code points: 141246 +# Total code points: 145893 # ================================================ @@ -9174,8 +9288,8 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 01BC..01BF ; XID_Continue # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN 01C0..01C3 ; XID_Continue # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK 01C4..0293 ; XID_Continue # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL -0294 ; XID_Continue # Lo LATIN LETTER GLOTTAL STOP -0295..02AF ; XID_Continue # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +0294..0295 ; XID_Continue # Lo [2] LATIN LETTER GLOTTAL STOP..LATIN LETTER PHARYNGEAL VOICED FRICATIVE +0296..02AF ; XID_Continue # L& [26] LATIN LETTER INVERTED GLOTTAL STOP..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL 02B0..02C1 ; XID_Continue # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP 02C6..02D1 ; XID_Continue # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON 02E0..02E4 ; XID_Continue # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP @@ -9250,7 +9364,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 0859..085B ; XID_Continue # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK 0860..086A ; XID_Continue # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 0870..0887 ; XID_Continue # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT -0889..088E ; XID_Continue # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL +0889..088F ; XID_Continue # Lo [7] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC LETTER NOON WITH RING ABOVE 0897..089F ; XID_Continue # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08A0..08C8 ; XID_Continue # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF 08C9 ; XID_Continue # Lm ARABIC SMALL FARSI YEH @@ -9400,7 +9514,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 0C4A..0C4D ; XID_Continue # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA 0C55..0C56 ; XID_Continue # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK 0C58..0C5A ; XID_Continue # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA -0C5D ; XID_Continue # Lo TELUGU LETTER NAKAARA POLLU +0C5C..0C5D ; XID_Continue # Lo [2] TELUGU ARCHAIC SHRII..TELUGU LETTER NAKAARA POLLU 0C60..0C61 ; XID_Continue # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL 0C62..0C63 ; XID_Continue # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL 0C66..0C6F ; XID_Continue # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE @@ -9422,7 +9536,7 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 0CCA..0CCB ; XID_Continue # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO 0CCC..0CCD ; XID_Continue # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA 0CD5..0CD6 ; XID_Continue # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK -0CDD..0CDE ; XID_Continue # Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA +0CDC..0CDE ; XID_Continue # Lo [3] KANNADA ARCHAIC SHRII..KANNADA LETTER FA 0CE0..0CE1 ; XID_Continue # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL 0CE2..0CE3 ; XID_Continue # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL 0CE6..0CEF ; XID_Continue # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE @@ -9639,7 +9753,8 @@ FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGU 1A90..1A99 ; XID_Continue # Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE 1AA7 ; XID_Continue # Lm TAI THAM SIGN MAI YAMOK 1AB0..1ABD ; XID_Continue # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW -1ABF..1ACE ; XID_Continue # Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T +1ABF..1ADD ; XID_Continue # Mn [31] COMBINING LATIN SMALL LETTER W BELOW..COMBINING DOT-AND-RING BELOW +1AE0..1AEB ; XID_Continue # Mn [12] COMBINING LEFT TACK ABOVE..COMBINING DOUBLE RIGHTWARDS ARROW ABOVE 1B00..1B03 ; XID_Continue # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG 1B04 ; XID_Continue # Mc BALINESE SIGN BISAH 1B05..1B33 ; XID_Continue # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA @@ -9827,11 +9942,8 @@ A771..A787 ; XID_Continue # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETT A788 ; XID_Continue # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A78B..A78E ; XID_Continue # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; XID_Continue # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CD ; XID_Continue # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE -A7D0..A7D1 ; XID_Continue # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G -A7D3 ; XID_Continue # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7DC ; XID_Continue # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE -A7F2..A7F4 ; XID_Continue # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q +A790..A7DC ; XID_Continue # L& [77] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER LAMBDA WITH STROKE +A7F1..A7F4 ; XID_Continue # Lm [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; XID_Continue # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; XID_Continue # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; XID_Continue # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -10044,6 +10156,7 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 108F4..108F5 ; XID_Continue # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW 10900..10915 ; XID_Continue # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU 10920..10939 ; XID_Continue # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C +10940..10959 ; XID_Continue # Lo [26] SIDETIC LETTER N01..SIDETIC LETTER N26 10980..109B7 ; XID_Continue # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA 109BE..109BF ; XID_Continue # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN 10A00 ; XID_Continue # Lo KHAROSHTHI LETTER A @@ -10082,7 +10195,9 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 10EAB..10EAC ; XID_Continue # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK 10EB0..10EB1 ; XID_Continue # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE 10EC2..10EC4 ; XID_Continue # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW -10EFC..10EFF ; XID_Continue # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA +10EC5 ; XID_Continue # Lm ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW +10EC6..10EC7 ; XID_Continue # Lo [2] ARABIC LETTER THIN NOON..ARABIC LETTER YEH WITH FOUR DOTS BELOW +10EFA..10EFF ; XID_Continue # Mn [6] ARABIC DOUBLE VERTICAL BAR BELOW..ARABIC SMALL LOW WORD MADDA 10F00..10F1C ; XID_Continue # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL 10F27 ; XID_Continue # Lo OLD SOGDIAN LIGATURE AYIN-DALETH 10F30..10F45 ; XID_Continue # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN @@ -10309,6 +10424,12 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 11A98..11A99 ; XID_Continue # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER 11A9D ; XID_Continue # Lo SOYOMBO MARK PLUTA 11AB0..11AF8 ; XID_Continue # Lo [73] CANADIAN SYLLABICS NATTILIK HI..PAU CIN HAU GLOTTAL STOP FINAL +11B60 ; XID_Continue # Mn SHARADA VOWEL SIGN OE +11B61 ; XID_Continue # Mc SHARADA VOWEL SIGN OOE +11B62..11B64 ; XID_Continue # Mn [3] SHARADA VOWEL SIGN UE..SHARADA VOWEL SIGN SHORT E +11B65 ; XID_Continue # Mc SHARADA VOWEL SIGN SHORT O +11B66 ; XID_Continue # Mn SHARADA VOWEL SIGN CANDRA E +11B67 ; XID_Continue # Mc SHARADA VOWEL SIGN CANDRA O 11BC0..11BE0 ; XID_Continue # Lo [33] SUNUWAR LETTER DEVI..SUNUWAR LETTER KLOKO 11BF0..11BF9 ; XID_Continue # Nd [10] SUNUWAR DIGIT ZERO..SUNUWAR DIGIT NINE 11C00..11C08 ; XID_Continue # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L @@ -10349,6 +10470,10 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 11D97 ; XID_Continue # Mn GUNJALA GONDI VIRAMA 11D98 ; XID_Continue # Lo GUNJALA GONDI OM 11DA0..11DA9 ; XID_Continue # Nd [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE +11DB0..11DD8 ; XID_Continue # Lo [41] TOLONG SIKI LETTER I..TOLONG SIKI LETTER RRH +11DD9 ; XID_Continue # Lm TOLONG SIKI SIGN SELA +11DDA..11DDB ; XID_Continue # Lo [2] TOLONG SIKI SIGN HECAKA..TOLONG SIKI UNGGA +11DE0..11DE9 ; XID_Continue # Nd [10] TOLONG SIKI DIGIT ZERO..TOLONG SIKI DIGIT NINE 11EE0..11EF2 ; XID_Continue # Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA 11EF3..11EF4 ; XID_Continue # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U 11EF5..11EF6 ; XID_Continue # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O @@ -10399,6 +10524,8 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 16D6B..16D6C ; XID_Continue # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT 16D70..16D79 ; XID_Continue # Nd [10] KIRAT RAI DIGIT ZERO..KIRAT RAI DIGIT NINE 16E40..16E7F ; XID_Continue # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16EA0..16EB8 ; XID_Continue # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY +16EBB..16ED3 ; XID_Continue # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY 16F00..16F4A ; XID_Continue # Lo [75] MIAO LETTER PA..MIAO LETTER RTE 16F4F ; XID_Continue # Mn MIAO SIGN CONSONANT MODIFIER BAR 16F50 ; XID_Continue # Lo MIAO LETTER NASALIZATION @@ -10409,9 +10536,11 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 16FE3 ; XID_Continue # Lm OLD CHINESE ITERATION MARK 16FE4 ; XID_Continue # Mn KHITAN SMALL SCRIPT FILLER 16FF0..16FF1 ; XID_Continue # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY -17000..187F7 ; XID_Continue # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 -18800..18CD5 ; XID_Continue # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 -18CFF..18D08 ; XID_Continue # Lo [10] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D08 +16FF2..16FF3 ; XID_Continue # Lm [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER +16FF4..16FF6 ; XID_Continue # Nl [3] YANGQIN SIGN SLOW ONE BEAT..YANGQIN SIGN SLOW TWO BEATS +17000..18CD5 ; XID_Continue # Lo [7382] TANGUT IDEOGRAPH-17000..KHITAN SMALL SCRIPT CHARACTER-18CD5 +18CFF..18D1E ; XID_Continue # Lo [32] KHITAN SMALL SCRIPT CHARACTER-18CFF..TANGUT IDEOGRAPH-18D1E +18D80..18DF2 ; XID_Continue # Lo [115] TANGUT COMPONENT-769..TANGUT COMPONENT-883 1AFF0..1AFF3 ; XID_Continue # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 1AFF5..1AFFB ; XID_Continue # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 1AFFD..1AFFE ; XID_Continue # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 @@ -10502,6 +10631,17 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 1E5EE..1E5EF ; XID_Continue # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR 1E5F0 ; XID_Continue # Lo OL ONAL SIGN HODDOND 1E5F1..1E5FA ; XID_Continue # Nd [10] OL ONAL DIGIT ZERO..OL ONAL DIGIT NINE +1E6C0..1E6DE ; XID_Continue # Lo [31] TAI YO LETTER LOW KO..TAI YO LETTER HIGH KVO +1E6E0..1E6E2 ; XID_Continue # Lo [3] TAI YO LETTER AA..TAI YO LETTER UE +1E6E3 ; XID_Continue # Mn TAI YO SIGN UE +1E6E4..1E6E5 ; XID_Continue # Lo [2] TAI YO LETTER U..TAI YO LETTER AE +1E6E6 ; XID_Continue # Mn TAI YO SIGN AU +1E6E7..1E6ED ; XID_Continue # Lo [7] TAI YO LETTER O..TAI YO LETTER AUE +1E6EE..1E6EF ; XID_Continue # Mn [2] TAI YO SIGN AY..TAI YO SIGN ANG +1E6F0..1E6F4 ; XID_Continue # Lo [5] TAI YO LETTER AN..TAI YO LETTER AP +1E6F5 ; XID_Continue # Mn TAI YO SIGN OM +1E6FE ; XID_Continue # Lo TAI YO SYMBOL MUEANG +1E6FF ; XID_Continue # Lm TAI YO XAM LAI 1E7E0..1E7E6 ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO 1E7E8..1E7EB ; XID_Continue # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE 1E7ED..1E7EE ; XID_Continue # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE @@ -10547,17 +10687,16 @@ FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HA 1EEAB..1EEBB ; XID_Continue # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 1FBF0..1FBF9 ; XID_Continue # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE 20000..2A6DF ; XID_Continue # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF -2A700..2B739 ; XID_Continue # Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 -2B740..2B81D ; XID_Continue # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D -2B820..2CEA1 ; XID_Continue # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2A700..2B81D ; XID_Continue # Lo [4382] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B81D +2B820..2CEAD ; XID_Continue # Lo [5774] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEAD 2CEB0..2EBE0 ; XID_Continue # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 2EBF0..2EE5D ; XID_Continue # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D 2F800..2FA1D ; XID_Continue # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D 30000..3134A ; XID_Continue # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A -31350..323AF ; XID_Continue # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF +31350..33479 ; XID_Continue # Lo [8490] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-33479 E0100..E01EF ; XID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 144522 +# Total code points: 149221 # ================================================ @@ -10778,7 +10917,8 @@ E01F0..E0FFF ; Default_Ignorable_Code_Point # Cn [3600] .... -2B76..2B95 ; Pattern_Syntax # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW -2B96 ; Pattern_Syntax # Cn -2B97..2BFF ; Pattern_Syntax # So [105] SYMBOL FOR TYPE A ELECTRONICS..HELLSCHREIBER PAUSE SYMBOL +2B76..2BFF ; Pattern_Syntax # So [138] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..HELLSCHREIBER PAUSE SYMBOL 2E00..2E01 ; Pattern_Syntax # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER 2E02 ; Pattern_Syntax # Pi LEFT SUBSTITUTION BRACKET 2E03 ; Pattern_Syntax # Pf RIGHT SUBSTITUTION BRACKET diff --git a/src/java.base/share/data/unicodedata/PropertyValueAliases.txt b/src/java.base/share/data/unicodedata/PropertyValueAliases.txt index 97980e2d902..b92662eda28 100644 --- a/src/java.base/share/data/unicodedata/PropertyValueAliases.txt +++ b/src/java.base/share/data/unicodedata/PropertyValueAliases.txt @@ -1,6 +1,6 @@ -# PropertyValueAliases-16.0.0.txt -# Date: 2024-07-30, 19:59:00 GMT -# Copyright (c) 2024 Unicode, Inc. +# PropertyValueAliases-17.0.0.txt +# Date: 2025-06-30, 06:16:21 GMT +# © 2025 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use and license, see https://www.unicode.org/terms_of_use.html # @@ -93,6 +93,7 @@ age; 14.0 ; V14_0 age; 15.0 ; V15_0 age; 15.1 ; V15_1 age; 16.0 ; V16_0 +age; 17.0 ; V17_0 age; NA ; Unassigned # Alphabetic (Alpha) @@ -179,6 +180,7 @@ blk; Bamum_Sup ; Bamum_Supplement blk; Bassa_Vah ; Bassa_Vah blk; Batak ; Batak blk; Bengali ; Bengali +blk; Beria_Erfe ; Beria_Erfe blk; Bhaiksuki ; Bhaiksuki blk; Block_Elements ; Block_Elements blk; Bopomofo ; Bopomofo @@ -211,6 +213,7 @@ blk; CJK_Ext_F ; CJK_Unified_Ideographs_Extension_F blk; CJK_Ext_G ; CJK_Unified_Ideographs_Extension_G blk; CJK_Ext_H ; CJK_Unified_Ideographs_Extension_H blk; CJK_Ext_I ; CJK_Unified_Ideographs_Extension_I +blk; CJK_Ext_J ; CJK_Unified_Ideographs_Extension_J blk; CJK_Radicals_Sup ; CJK_Radicals_Supplement blk; CJK_Strokes ; CJK_Strokes blk; CJK_Symbols ; CJK_Symbols_And_Punctuation @@ -360,6 +363,7 @@ blk; Misc_Math_Symbols_A ; Miscellaneous_Mathematical_Symbols_A blk; Misc_Math_Symbols_B ; Miscellaneous_Mathematical_Symbols_B blk; Misc_Pictographs ; Miscellaneous_Symbols_And_Pictographs blk; Misc_Symbols ; Miscellaneous_Symbols +blk; Misc_Symbols_Sup ; Miscellaneous_Symbols_Supplement blk; Misc_Technical ; Miscellaneous_Technical blk; Modi ; Modi blk; Modifier_Letters ; Spacing_Modifier_Letters @@ -419,9 +423,11 @@ blk; Runic ; Runic blk; Samaritan ; Samaritan blk; Saurashtra ; Saurashtra blk; Sharada ; Sharada +blk; Sharada_Sup ; Sharada_Supplement blk; Shavian ; Shavian blk; Shorthand_Format_Controls ; Shorthand_Format_Controls blk; Siddham ; Siddham +blk; Sidetic ; Sidetic blk; Sinhala ; Sinhala blk; Sinhala_Archaic_Numbers ; Sinhala_Archaic_Numbers blk; Small_Forms ; Small_Form_Variants @@ -456,12 +462,14 @@ blk; Tai_Le ; Tai_Le blk; Tai_Tham ; Tai_Tham blk; Tai_Viet ; Tai_Viet blk; Tai_Xuan_Jing ; Tai_Xuan_Jing_Symbols +blk; Tai_Yo ; Tai_Yo blk; Takri ; Takri blk; Tamil ; Tamil blk; Tamil_Sup ; Tamil_Supplement blk; Tangsa ; Tangsa blk; Tangut ; Tangut blk; Tangut_Components ; Tangut_Components +blk; Tangut_Components_Sup ; Tangut_Components_Supplement blk; Tangut_Sup ; Tangut_Supplement blk; Telugu ; Telugu blk; Thaana ; Thaana @@ -470,6 +478,7 @@ blk; Tibetan ; Tibetan blk; Tifinagh ; Tifinagh blk; Tirhuta ; Tirhuta blk; Todhri ; Todhri +blk; Tolong_Siki ; Tolong_Siki blk; Toto ; Toto blk; Transport_And_Map ; Transport_And_Map_Symbols blk; Tulu_Tigalari ; Tulu_Tigalari @@ -878,7 +887,7 @@ InPC; Bottom_And_Left ; Bottom_And_Left InPC; Bottom_And_Right ; Bottom_And_Right InPC; Left ; Left InPC; Left_And_Right ; Left_And_Right -InPC; NA ; NA +InPC; NA ; Not_Applicable InPC; Overstruck ; Overstruck InPC; Right ; Right InPC; Top ; Top @@ -1088,6 +1097,7 @@ jg ; Taw ; Taw jg ; Teh_Marbuta ; Teh_Marbuta jg ; Teh_Marbuta_Goal ; Teh_Marbuta_Goal ; Hamza_On_Heh_Goal jg ; Teth ; Teth +jg ; Thin_Noon ; Thin_Noon jg ; Thin_Yeh ; Thin_Yeh jg ; Vertical_Tail ; Vertical_Tail jg ; Waw ; Waw @@ -1131,6 +1141,7 @@ lb ; EX ; Exclamation lb ; GL ; Glue lb ; H2 ; H2 lb ; H3 ; H3 +lb ; HH ; Unambiguous_Hyphen lb ; HL ; Hebrew_Letter lb ; HY ; Hyphen lb ; ID ; Ideographic @@ -1319,6 +1330,7 @@ sc ; Bamu ; Bamum sc ; Bass ; Bassa_Vah sc ; Batk ; Batak sc ; Beng ; Bengali +sc ; Berf ; Beria_Erfe sc ; Bhks ; Bhaiksuki sc ; Bopo ; Bopomofo sc ; Brah ; Brahmi @@ -1438,6 +1450,7 @@ sc ; Sgnw ; SignWriting sc ; Shaw ; Shavian sc ; Shrd ; Sharada sc ; Sidd ; Siddham +sc ; Sidt ; Sidetic sc ; Sind ; Khudawadi sc ; Sinh ; Sinhala sc ; Sogd ; Sogdian @@ -1455,6 +1468,7 @@ sc ; Talu ; New_Tai_Lue sc ; Taml ; Tamil sc ; Tang ; Tangut sc ; Tavt ; Tai_Viet +sc ; Tayo ; Tai_Yo sc ; Telu ; Telugu sc ; Tfng ; Tifinagh sc ; Tglg ; Tagalog @@ -1464,6 +1478,7 @@ sc ; Tibt ; Tibetan sc ; Tirh ; Tirhuta sc ; Tnsa ; Tangsa sc ; Todr ; Todhri +sc ; Tols ; Tolong_Siki sc ; Toto ; Toto sc ; Tutg ; Tulu_Tigalari sc ; Ugar ; Ugaritic @@ -1705,4 +1720,16 @@ kEH_NoMirror; Y ; Yes ; T kEH_NoRotate; N ; No ; F ; False kEH_NoRotate; Y ; Yes ; T ; True +# kMandarin (cjkMandarin) + +# @missing: 0000..10FFFF; kMandarin; + +# kTotalStrokes (cjkTotalStrokes) + +# @missing: 0000..10FFFF; kTotalStrokes; + +# kUnihanCore2020 (cjkUnihanCore2020) + +# @missing: 0000..10FFFF; kUnihanCore2020; + # EOF diff --git a/src/java.base/share/data/unicodedata/ReadMe.txt b/src/java.base/share/data/unicodedata/ReadMe.txt index 81d489a0575..268f62b8a93 100644 --- a/src/java.base/share/data/unicodedata/ReadMe.txt +++ b/src/java.base/share/data/unicodedata/ReadMe.txt @@ -1,17 +1,24 @@ # Unicode Character Database -# Date: 2024-08-25 -# Copyright (c) 2024 Unicode, Inc. +# Date: 2025-08-15 +# © 2025 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use and license, see https://www.unicode.org/terms_of_use.html # # For documentation, see the following: -# NamesList.html +# ucd/NamesList.html # UAX #38, "Unicode Han Database (Unihan)" +# UAX #42, "Unicode Character Database in XML" # UAX #44, "Unicode Character Database" # UTS #51, "Unicode Emoji" # UAX #57, "Unicode Egyptian Hieroglyph Database" # -# The UAXes and UTS #51 can be accessed at https://www.unicode.org/versions/Unicode16.0.0/ +# The UAXes and UTS #51 can be accessed at https://www.unicode.org/versions/Unicode17.0.0/ -This directory contains final data files -for the Unicode Character Database, for Version 16.0.0 of the Unicode Standard. +This directory contains the final data files +for Version 17.0.0 of the Unicode Standard. + +The "charts" subdirectory contains an archival set of +pdf code charts corresponding exactly to Version 17.0.0. + +The other subdirectories contain the data files for the +Unicode Character Database and for the synchronized Unicode Technical Standards. diff --git a/src/java.base/share/data/unicodedata/Scripts.txt b/src/java.base/share/data/unicodedata/Scripts.txt index 14d48d94162..5574fdd6ae3 100644 --- a/src/java.base/share/data/unicodedata/Scripts.txt +++ b/src/java.base/share/data/unicodedata/Scripts.txt @@ -1,6 +1,6 @@ -# Scripts-16.0.0.txt -# Date: 2024-04-30, 21:48:40 GMT -# Copyright (c) 2024 Unicode, Inc. +# Scripts-17.0.0.txt +# Date: 2025-07-24, 13:28:55 GMT +# © 2025 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use and license, see https://www.unicode.org/terms_of_use.html # @@ -154,7 +154,7 @@ 208A..208C ; Common # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN 208D ; Common # Ps SUBSCRIPT LEFT PARENTHESIS 208E ; Common # Pe SUBSCRIPT RIGHT PARENTHESIS -20A0..20C0 ; Common # Sc [33] EURO-CURRENCY SIGN..SOM SIGN +20A0..20C1 ; Common # Sc [34] EURO-CURRENCY SIGN..SAUDI RIYAL SIGN 2100..2101 ; Common # So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT 2102 ; Common # L& DOUBLE-STRUCK CAPITAL C 2103..2106 ; Common # So [4] DEGREE CELSIUS..CADA UNA @@ -306,8 +306,7 @@ 2B45..2B46 ; Common # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW 2B47..2B4C ; Common # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR 2B4D..2B73 ; Common # So [39] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR -2B76..2B95 ; Common # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW -2B97..2BFF ; Common # So [105] SYMBOL FOR TYPE A ELECTRONICS..HELLSCHREIBER PAUSE SYMBOL +2B76..2BFF ; Common # So [138] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..HELLSCHREIBER PAUSE SYMBOL 2E00..2E01 ; Common # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER 2E02 ; Common # Pi LEFT SUBSTITUTION BRACKET 2E03 ; Common # Pf RIGHT SUBSTITUTION BRACKET @@ -524,7 +523,11 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1BCA0..1BCA3 ; Common # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP 1CC00..1CCEF ; Common # So [240] UP-POINTING GO-KART..OUTLINED LATIN CAPITAL LETTER Z 1CCF0..1CCF9 ; Common # Nd [10] OUTLINED DIGIT ZERO..OUTLINED DIGIT NINE +1CCFA..1CCFC ; Common # So [3] SNAKE SYMBOL..NOSE SYMBOL 1CD00..1CEB3 ; Common # So [436] BLOCK OCTANT-3..BLACK RIGHT TRIANGLE CARET +1CEBA..1CED0 ; Common # So [23] FRAGILE SYMBOL..LEUKOTHEA +1CEE0..1CEEF ; Common # So [16] GEOMANTIC FIGURE POPULUS..GEOMANTIC FIGURE VIA +1CEF0 ; Common # Sm MEDIUM SMALL WHITE CIRCLE WITH HORIZONTAL BAR 1CF50..1CFC3 ; Common # So [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK 1D000..1D0F5 ; Common # So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO 1D100..1D126 ; Common # So [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2 @@ -605,11 +608,10 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1F260..1F265 ; Common # So [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI 1F300..1F3FA ; Common # So [251] CYCLONE..AMPHORA 1F3FB..1F3FF ; Common # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 -1F400..1F6D7 ; Common # So [728] RAT..ELEVATOR +1F400..1F6D8 ; Common # So [729] RAT..LANDSLIDE 1F6DC..1F6EC ; Common # So [17] WIRELESS..AIRPLANE ARRIVING 1F6F0..1F6FC ; Common # So [13] SATELLITE..ROLLER SKATE -1F700..1F776 ; Common # So [119] ALCHEMICAL SYMBOL FOR QUINTESSENCE..LUNAR ECLIPSE -1F77B..1F7D9 ; Common # So [95] HAUMEA..NINE POINTED WHITE STAR +1F700..1F7D9 ; Common # So [218] ALCHEMICAL SYMBOL FOR QUINTESSENCE..NINE POINTED WHITE STAR 1F7E0..1F7EB ; Common # So [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE 1F7F0 ; Common # So HEAVY EQUALS SIGN 1F800..1F80B ; Common # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD @@ -619,21 +621,24 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1F890..1F8AD ; Common # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS 1F8B0..1F8BB ; Common # So [12] ARROW POINTING UPWARDS THEN NORTH WEST..SOUTH WEST ARROW FROM BAR 1F8C0..1F8C1 ; Common # So [2] LEFTWARDS ARROW FROM DOWNWARDS ARROW..RIGHTWARDS ARROW FROM DOWNWARDS ARROW -1F900..1FA53 ; Common # So [340] CIRCLED CROSS FORMEE WITH FOUR DOTS..BLACK CHESS KNIGHT-BISHOP +1F8D0..1F8D8 ; Common # Sm [9] LONG RIGHTWARDS ARROW OVER LONG LEFTWARDS ARROW..LONG LEFT RIGHT ARROW WITH DEPENDENT LOBE +1F900..1FA57 ; Common # So [344] CIRCLED CROSS FORMEE WITH FOUR DOTS..BLACK CHESS ALFIL 1FA60..1FA6D ; Common # So [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER 1FA70..1FA7C ; Common # So [13] BALLET SHOES..CRUTCH -1FA80..1FA89 ; Common # So [10] YO-YO..HARP -1FA8F..1FAC6 ; Common # So [56] SHOVEL..FINGERPRINT -1FACE..1FADC ; Common # So [15] MOOSE..ROOT VEGETABLE -1FADF..1FAE9 ; Common # So [11] SPLATTER..FACE WITH BAGS UNDER EYES -1FAF0..1FAF8 ; Common # So [9] HAND WITH INDEX FINGER AND THUMB CROSSED..RIGHTWARDS PUSHING HAND +1FA80..1FA8A ; Common # So [11] YO-YO..TROMBONE +1FA8E..1FAC6 ; Common # So [57] TREASURE CHEST..FINGERPRINT +1FAC8 ; Common # So HAIRY CREATURE +1FACD..1FADC ; Common # So [16] ORCA..ROOT VEGETABLE +1FADF..1FAEA ; Common # So [12] SPLATTER..DISTORTED FACE +1FAEF..1FAF8 ; Common # So [10] FIGHT CLOUD..RIGHTWARDS PUSHING HAND 1FB00..1FB92 ; Common # So [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK 1FB94..1FBEF ; Common # So [92] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..TOP LEFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLE 1FBF0..1FBF9 ; Common # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE +1FBFA ; Common # So ALARM BELL SYMBOL E0001 ; Common # Cf LANGUAGE TAG E0020..E007F ; Common # Cf [96] TAG SPACE..CANCEL TAG -# Total code points: 9053 +# Total code points: 9123 # ================================================ @@ -648,8 +653,8 @@ E0020..E007F ; Common # Cf [96] TAG SPACE..CANCEL TAG 01BC..01BF ; Latin # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN 01C0..01C3 ; Latin # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK 01C4..0293 ; Latin # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL -0294 ; Latin # Lo LATIN LETTER GLOTTAL STOP -0295..02AF ; Latin # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +0294..0295 ; Latin # Lo [2] LATIN LETTER GLOTTAL STOP..LATIN LETTER PHARYNGEAL VOICED FRICATIVE +0296..02AF ; Latin # L& [26] LATIN LETTER INVERTED GLOTTAL STOP..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL 02B0..02B8 ; Latin # Lm [9] MODIFIER LETTER SMALL H..MODIFIER LETTER SMALL Y 02E0..02E4 ; Latin # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP 1D00..1D25 ; Latin # L& [38] LATIN LETTER SMALL CAPITAL A..LATIN LETTER AIN @@ -676,11 +681,8 @@ A770 ; Latin # Lm MODIFIER LETTER US A771..A787 ; Latin # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T A78B..A78E ; Latin # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; Latin # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7CD ; Latin # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE -A7D0..A7D1 ; Latin # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G -A7D3 ; Latin # L& LATIN SMALL LETTER DOUBLE THORN -A7D5..A7DC ; Latin # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE -A7F2..A7F4 ; Latin # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q +A790..A7DC ; Latin # L& [77] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER LAMBDA WITH STROKE +A7F1..A7F4 ; Latin # Lm [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q A7F5..A7F6 ; Latin # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H A7F7 ; Latin # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; Latin # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -702,7 +704,7 @@ FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 1DF0B..1DF1E ; Latin # L& [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL 1DF25..1DF2A ; Latin # L& [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK -# Total code points: 1487 +# Total code points: 1492 # ================================================ @@ -869,7 +871,7 @@ FB46..FB4F ; Hebrew # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATU 0750..077F ; Arabic # Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE 0870..0887 ; Arabic # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT 0888 ; Arabic # Sk ARABIC RAISED ROUND DOT -0889..088E ; Arabic # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL +0889..088F ; Arabic # Lo [7] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC LETTER NOON WITH RING ABOVE 0890..0891 ; Arabic # Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE 0897..089F ; Arabic # Mn [9] ARABIC PEPET..ARABIC HALF MADDA OVER MADDA 08A0..08C8 ; Arabic # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF @@ -878,11 +880,13 @@ FB46..FB4F ; Hebrew # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATU 08E3..08FF ; Arabic # Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA FB50..FBB1 ; Arabic # Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM FBB2..FBC2 ; Arabic # Sk [17] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL WASLA ABOVE +FBC3..FBD2 ; Arabic # So [16] ARABIC LIGATURE JALLA WA-ALAA..ARABIC LIGATURE ALAYHI AR-RAHMAH FBD3..FD3D ; Arabic # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM FD40..FD4F ; Arabic # So [16] ARABIC LIGATURE RAHIMAHU ALLAAH..ARABIC LIGATURE RAHIMAHUM ALLAAH FD50..FD8F ; Arabic # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM +FD90..FD91 ; Arabic # So [2] ARABIC LIGATURE RAHMATU ALLAAHI ALAYH..ARABIC LIGATURE RAHMATU ALLAAHI ALAYHAA FD92..FDC7 ; Arabic # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM -FDCF ; Arabic # So ARABIC LIGATURE SALAAMUHU ALAYNAA +FDC8..FDCF ; Arabic # So [8] ARABIC LIGATURE RAHIMAHU ALLAAH TAAALAA..ARABIC LIGATURE SALAAMUHU ALAYNAA FDF0..FDFB ; Arabic # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU FDFC ; Arabic # Sc RIAL SIGN FDFD..FDFF ; Arabic # So [3] ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM..ARABIC LIGATURE AZZA WA JALL @@ -890,7 +894,11 @@ FE70..FE74 ; Arabic # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN FE76..FEFC ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM 10E60..10E7E ; Arabic # No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS 10EC2..10EC4 ; Arabic # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW -10EFC..10EFF ; Arabic # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA +10EC5 ; Arabic # Lm ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW +10EC6..10EC7 ; Arabic # Lo [2] ARABIC LETTER THIN NOON..ARABIC LETTER YEH WITH FOUR DOTS BELOW +10ED0 ; Arabic # Po ARABIC BIBLICAL END OF VERSE +10ED1..10ED8 ; Arabic # So [8] ARABIC LIGATURE ALAYHAA AS-SALAATU WAS-SALAAM..ARABIC LIGATURE NAWWARA ALLAAHU MARQADAH +10EFA..10EFF ; Arabic # Mn [6] ARABIC DOUBLE VERTICAL BAR BELOW..ARABIC SMALL LOW WORD MADDA 1EE00..1EE03 ; Arabic # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL 1EE05..1EE1F ; Arabic # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF 1EE21..1EE22 ; Arabic # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM @@ -926,7 +934,7 @@ FE76..FEFC ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LA 1EEAB..1EEBB ; Arabic # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 1EEF0..1EEF1 ; Arabic # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL -# Total code points: 1373 +# Total code points: 1413 # ================================================ @@ -1155,7 +1163,7 @@ A8FF ; Devanagari # Mn DEVANAGARI VOWEL SIGN AY 0C4A..0C4D ; Telugu # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA 0C55..0C56 ; Telugu # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK 0C58..0C5A ; Telugu # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA -0C5D ; Telugu # Lo TELUGU LETTER NAKAARA POLLU +0C5C..0C5D ; Telugu # Lo [2] TELUGU ARCHAIC SHRII..TELUGU LETTER NAKAARA POLLU 0C60..0C61 ; Telugu # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL 0C62..0C63 ; Telugu # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL 0C66..0C6F ; Telugu # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE @@ -1163,7 +1171,7 @@ A8FF ; Devanagari # Mn DEVANAGARI VOWEL SIGN AY 0C78..0C7E ; Telugu # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR 0C7F ; Telugu # So TELUGU SIGN TUUMU -# Total code points: 100 +# Total code points: 101 # ================================================ @@ -1186,14 +1194,14 @@ A8FF ; Devanagari # Mn DEVANAGARI VOWEL SIGN AY 0CCA..0CCB ; Kannada # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO 0CCC..0CCD ; Kannada # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA 0CD5..0CD6 ; Kannada # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK -0CDD..0CDE ; Kannada # Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA +0CDC..0CDE ; Kannada # Lo [3] KANNADA ARCHAIC SHRII..KANNADA LETTER FA 0CE0..0CE1 ; Kannada # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL 0CE2..0CE3 ; Kannada # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL 0CE6..0CEF ; Kannada # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE 0CF1..0CF2 ; Kannada # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA 0CF3 ; Kannada # Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT -# Total code points: 91 +# Total code points: 92 # ================================================ @@ -1594,17 +1602,18 @@ FA70..FAD9 ; Han # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILI 16FE2 ; Han # Po OLD CHINESE HOOK MARK 16FE3 ; Han # Lm OLD CHINESE ITERATION MARK 16FF0..16FF1 ; Han # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY +16FF2..16FF3 ; Han # Lm [2] CHINESE SMALL SIMPLIFIED ER..CHINESE SMALL TRADITIONAL ER +16FF4..16FF6 ; Han # Nl [3] YANGQIN SIGN SLOW ONE BEAT..YANGQIN SIGN SLOW TWO BEATS 20000..2A6DF ; Han # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF -2A700..2B739 ; Han # Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 -2B740..2B81D ; Han # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D -2B820..2CEA1 ; Han # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2A700..2B81D ; Han # Lo [4382] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B81D +2B820..2CEAD ; Han # Lo [5774] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEAD 2CEB0..2EBE0 ; Han # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 2EBF0..2EE5D ; Han # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D 2F800..2FA1D ; Han # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D 30000..3134A ; Han # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A -31350..323AF ; Han # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF +31350..33479 ; Han # Lo [8490] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-33479 -# Total code points: 99030 +# Total code points: 103351 # ================================================ @@ -1647,7 +1656,8 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE 0951..0954 ; Inherited # Mn [4] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI ACUTE ACCENT 1AB0..1ABD ; Inherited # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW 1ABE ; Inherited # Me COMBINING PARENTHESES OVERLAY -1ABF..1ACE ; Inherited # Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T +1ABF..1ADD ; Inherited # Mn [31] COMBINING LATIN SMALL LETTER W BELOW..COMBINING DOT-AND-RING BELOW +1AE0..1AEB ; Inherited # Mn [12] COMBINING LEFT TACK ABOVE..COMBINING DOUBLE RIGHTWARDS ARROW ABOVE 1CD0..1CD2 ; Inherited # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA 1CD4..1CE0 ; Inherited # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA 1CE2..1CE8 ; Inherited # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL @@ -1676,7 +1686,7 @@ FE20..FE2D ; Inherited # Mn [14] COMBINING LIGATURE LEFT HALF..COMBINING CON 1D1AA..1D1AD ; Inherited # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 657 +# Total code points: 684 # ================================================ @@ -2347,8 +2357,14 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI 111DB ; Sharada # Po SHARADA SIGN SIDDHAM 111DC ; Sharada # Lo SHARADA HEADSTROKE 111DD..111DF ; Sharada # Po [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2 +11B60 ; Sharada # Mn SHARADA VOWEL SIGN OE +11B61 ; Sharada # Mc SHARADA VOWEL SIGN OOE +11B62..11B64 ; Sharada # Mn [3] SHARADA VOWEL SIGN UE..SHARADA VOWEL SIGN SHORT E +11B65 ; Sharada # Mc SHARADA VOWEL SIGN SHORT O +11B66 ; Sharada # Mn SHARADA VOWEL SIGN CANDRA E +11B67 ; Sharada # Mc SHARADA VOWEL SIGN CANDRA O -# Total code points: 96 +# Total code points: 104 # ================================================ @@ -2756,11 +2772,11 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI # ================================================ 16FE0 ; Tangut # Lm TANGUT ITERATION MARK -17000..187F7 ; Tangut # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 -18800..18AFF ; Tangut # Lo [768] TANGUT COMPONENT-001..TANGUT COMPONENT-768 -18D00..18D08 ; Tangut # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +17000..18AFF ; Tangut # Lo [6912] TANGUT IDEOGRAPH-17000..TANGUT COMPONENT-768 +18D00..18D1E ; Tangut # Lo [31] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D1E +18D80..18DF2 ; Tangut # Lo [115] TANGUT COMPONENT-769..TANGUT COMPONENT-883 -# Total code points: 6914 +# Total code points: 7059 # ================================================ @@ -3125,4 +3141,42 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI # Total code points: 80 +# ================================================ + +10940..10959 ; Sidetic # Lo [26] SIDETIC LETTER N01..SIDETIC LETTER N26 + +# Total code points: 26 + +# ================================================ + +1E6C0..1E6DE ; Tai_Yo # Lo [31] TAI YO LETTER LOW KO..TAI YO LETTER HIGH KVO +1E6E0..1E6E2 ; Tai_Yo # Lo [3] TAI YO LETTER AA..TAI YO LETTER UE +1E6E3 ; Tai_Yo # Mn TAI YO SIGN UE +1E6E4..1E6E5 ; Tai_Yo # Lo [2] TAI YO LETTER U..TAI YO LETTER AE +1E6E6 ; Tai_Yo # Mn TAI YO SIGN AU +1E6E7..1E6ED ; Tai_Yo # Lo [7] TAI YO LETTER O..TAI YO LETTER AUE +1E6EE..1E6EF ; Tai_Yo # Mn [2] TAI YO SIGN AY..TAI YO SIGN ANG +1E6F0..1E6F4 ; Tai_Yo # Lo [5] TAI YO LETTER AN..TAI YO LETTER AP +1E6F5 ; Tai_Yo # Mn TAI YO SIGN OM +1E6FE ; Tai_Yo # Lo TAI YO SYMBOL MUEANG +1E6FF ; Tai_Yo # Lm TAI YO XAM LAI + +# Total code points: 55 + +# ================================================ + +11DB0..11DD8 ; Tolong_Siki # Lo [41] TOLONG SIKI LETTER I..TOLONG SIKI LETTER RRH +11DD9 ; Tolong_Siki # Lm TOLONG SIKI SIGN SELA +11DDA..11DDB ; Tolong_Siki # Lo [2] TOLONG SIKI SIGN HECAKA..TOLONG SIKI UNGGA +11DE0..11DE9 ; Tolong_Siki # Nd [10] TOLONG SIKI DIGIT ZERO..TOLONG SIKI DIGIT NINE + +# Total code points: 54 + +# ================================================ + +16EA0..16EB8 ; Beria_Erfe # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY +16EBB..16ED3 ; Beria_Erfe # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY + +# Total code points: 50 + # EOF diff --git a/src/java.base/share/data/unicodedata/SpecialCasing.txt b/src/java.base/share/data/unicodedata/SpecialCasing.txt index 74700b5d321..1013344a6f2 100644 --- a/src/java.base/share/data/unicodedata/SpecialCasing.txt +++ b/src/java.base/share/data/unicodedata/SpecialCasing.txt @@ -1,6 +1,6 @@ -# SpecialCasing-16.0.0.txt -# Date: 2024-05-10, 22:49:00 GMT -# Copyright (c) 2024 Unicode, Inc. +# SpecialCasing-17.0.0.txt +# Date: 2025-07-31, 22:11:55 GMT +# © 2025 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use and license, see https://www.unicode.org/terms_of_use.html # @@ -47,8 +47,8 @@ # # A language ID is defined by BCP 47, with '-' and '_' treated equivalently. # -# A casing context for a character is defined by Section 3.13 Default Case Algorithms -# of The Unicode Standard. +# A casing context for a character is defined in the +# "Conformance" / "Default Case Algorithms" section of the core specification. # # Parsers of this file must be prepared to deal with future additions to this format: # * Additional contexts @@ -57,6 +57,10 @@ # ================================================================================ # Unconditional mappings +# The mappings in this section are not language-sensitive nor context-sensitive. +# +# Note that comments provide additional information but +# do not modify the case mapping algorithms in the core specification, chapter 3. # ================================================================================ # The German es-zed is special--the normal mapping is to SS. diff --git a/src/java.base/share/data/unicodedata/UnicodeData.txt b/src/java.base/share/data/unicodedata/UnicodeData.txt index 64258a37395..fca68e3e154 100644 --- a/src/java.base/share/data/unicodedata/UnicodeData.txt +++ b/src/java.base/share/data/unicodedata/UnicodeData.txt @@ -659,7 +659,7 @@ 0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7 0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;; 0294;LATIN LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;; -0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;; +0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Lo;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;; 0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;; 0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;; 0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;; @@ -2121,6 +2121,7 @@ 088C;ARABIC LETTER TAH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; 088D;ARABIC LETTER KEHEH WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;; 088E;ARABIC VERTICAL TAIL;Lo;0;AL;;;;;N;;;;; +088F;ARABIC LETTER NOON WITH RING ABOVE;Lo;0;AL;;;;;N;;;;; 0890;ARABIC POUND MARK ABOVE;Cf;0;AN;;;;;N;;;;; 0891;ARABIC PIASTRE MARK ABOVE;Cf;0;AN;;;;;N;;;;; 0897;ARABIC PEPET;Mn;230;NSM;;;;;N;;;;; @@ -2862,6 +2863,7 @@ 0C58;TELUGU LETTER TSA;Lo;0;L;;;;;N;;;;; 0C59;TELUGU LETTER DZA;Lo;0;L;;;;;N;;;;; 0C5A;TELUGU LETTER RRRA;Lo;0;L;;;;;N;;;;; +0C5C;TELUGU ARCHAIC SHRII;Lo;0;L;;;;;N;;;;; 0C5D;TELUGU LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;; 0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; @@ -2958,6 +2960,7 @@ 0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;; 0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;; +0CDC;KANNADA ARCHAIC SHRII;Lo;0;L;;;;;N;;;;; 0CDD;KANNADA LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;; 0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;; 0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; @@ -6137,6 +6140,33 @@ 1ACC;COMBINING LATIN SMALL LETTER INSULAR G;Mn;230;NSM;;;;;N;;;;; 1ACD;COMBINING LATIN SMALL LETTER INSULAR R;Mn;230;NSM;;;;;N;;;;; 1ACE;COMBINING LATIN SMALL LETTER INSULAR T;Mn;230;NSM;;;;;N;;;;; +1ACF;COMBINING DOUBLE CARON;Mn;230;NSM;;;;;N;;;;; +1AD0;COMBINING VERTICAL-LINE-ACUTE;Mn;230;NSM;;;;;N;;;;; +1AD1;COMBINING GRAVE-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;; +1AD2;COMBINING VERTICAL-LINE-GRAVE;Mn;230;NSM;;;;;N;;;;; +1AD3;COMBINING ACUTE-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;; +1AD4;COMBINING VERTICAL-LINE-MACRON;Mn;230;NSM;;;;;N;;;;; +1AD5;COMBINING MACRON-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;; +1AD6;COMBINING VERTICAL-LINE-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;; +1AD7;COMBINING VERTICAL-LINE-GRAVE-ACUTE;Mn;230;NSM;;;;;N;;;;; +1AD8;COMBINING MACRON-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;; +1AD9;COMBINING SHARP SIGN;Mn;230;NSM;;;;;N;;;;; +1ADA;COMBINING FLAT SIGN;Mn;230;NSM;;;;;N;;;;; +1ADB;COMBINING DOWN TACK ABOVE;Mn;230;NSM;;;;;N;;;;; +1ADC;COMBINING DIAERESIS WITH RAISED LEFT DOT;Mn;230;NSM;;;;;N;;;;; +1ADD;COMBINING DOT-AND-RING BELOW;Mn;220;NSM;;;;;N;;;;; +1AE0;COMBINING LEFT TACK ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE1;COMBINING RIGHT TACK ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE2;COMBINING MINUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE3;COMBINING INVERTED BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE4;COMBINING SQUARE ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE5;COMBINING SEAGULL ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE6;COMBINING DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;;;;; +1AE7;COMBINING DOUBLE ARCH ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE8;COMBINING EQUALS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; +1AE9;COMBINING LEFT ANGLE CENTRED ABOVE;Mn;230;NSM;;;;;N;;;;; +1AEA;COMBINING UPWARDS ARROW ABOVE;Mn;230;NSM;;;;;N;;;;; +1AEB;COMBINING DOUBLE RIGHTWARDS ARROW ABOVE;Mn;234;NSM;;;;;N;;;;; 1B00;BALINESE SIGN ULU RICEM;Mn;0;NSM;;;;;N;;;;; 1B01;BALINESE SIGN ULU CANDRA;Mn;0;NSM;;;;;N;;;;; 1B02;BALINESE SIGN CECEK;Mn;0;NSM;;;;;N;;;;; @@ -7545,6 +7575,7 @@ 20BE;LARI SIGN;Sc;0;ET;;;;;N;;;;; 20BF;BITCOIN SIGN;Sc;0;ET;;;;;N;;;;; 20C0;SOM SIGN;Sc;0;ET;;;;;N;;;;; +20C1;SAUDI RIYAL SIGN;Sc;0;ET;;;;;N;;;;; 20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;; 20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;; 20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;; @@ -10239,6 +10270,7 @@ 2B93;NEWLINE RIGHT;So;0;ON;;;;;N;;;;; 2B94;FOUR CORNER ARROWS CIRCLING ANTICLOCKWISE;So;0;ON;;;;;N;;;;; 2B95;RIGHTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; +2B96;EQUALS SIGN WITH INFINITY ABOVE;So;0;ON;;;;;N;;;;; 2B97;SYMBOL FOR TYPE A ELECTRONICS;So;0;ON;;;;;N;;;;; 2B98;THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; 2B99;THREE-D RIGHT-LIGHTED UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; @@ -14274,10 +14306,14 @@ A7CA;LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C9;;A7C9 A7CB;LATIN CAPITAL LETTER RAMS HORN;Lu;0;L;;;;;N;;;;0264; A7CC;LATIN CAPITAL LETTER S WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A7CD; A7CD;LATIN SMALL LETTER S WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A7CC;;A7CC +A7CE;LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE;Lu;0;L;;;;;N;;;;A7CF; +A7CF;LATIN SMALL LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;;;A7CE;;A7CE A7D0;LATIN CAPITAL LETTER CLOSED INSULAR G;Lu;0;L;;;;;N;;;;A7D1; A7D1;LATIN SMALL LETTER CLOSED INSULAR G;Ll;0;L;;;;;N;;;A7D0;;A7D0 -A7D3;LATIN SMALL LETTER DOUBLE THORN;Ll;0;L;;;;;N;;;;; -A7D5;LATIN SMALL LETTER DOUBLE WYNN;Ll;0;L;;;;;N;;;;; +A7D2;LATIN CAPITAL LETTER DOUBLE THORN;Lu;0;L;;;;;N;;;;A7D3; +A7D3;LATIN SMALL LETTER DOUBLE THORN;Ll;0;L;;;;;N;;;A7D2;;A7D2 +A7D4;LATIN CAPITAL LETTER DOUBLE WYNN;Lu;0;L;;;;;N;;;;A7D5; +A7D5;LATIN SMALL LETTER DOUBLE WYNN;Ll;0;L;;;;;N;;;A7D4;;A7D4 A7D6;LATIN CAPITAL LETTER MIDDLE SCOTS S;Lu;0;L;;;;;N;;;;A7D7; A7D7;LATIN SMALL LETTER MIDDLE SCOTS S;Ll;0;L;;;;;N;;;A7D6;;A7D6 A7D8;LATIN CAPITAL LETTER SIGMOID S;Lu;0;L;;;;;N;;;;A7D9; @@ -14285,6 +14321,7 @@ A7D9;LATIN SMALL LETTER SIGMOID S;Ll;0;L;;;;;N;;;A7D8;;A7D8 A7DA;LATIN CAPITAL LETTER LAMBDA;Lu;0;L;;;;;N;;;;A7DB; A7DB;LATIN SMALL LETTER LAMBDA;Ll;0;L;;;;;N;;;A7DA;;A7DA A7DC;LATIN CAPITAL LETTER LAMBDA WITH STROKE;Lu;0;L;;;;;N;;;;019B; +A7F1;MODIFIER LETTER CAPITAL S;Lm;0;L; 0053;;;;N;;;;; A7F2;MODIFIER LETTER CAPITAL C;Lm;0;L; 0043;;;;N;;;;; A7F3;MODIFIER LETTER CAPITAL F;Lm;0;L; 0046;;;;N;;;;; A7F4;MODIFIER LETTER CAPITAL Q;Lm;0;L; 0051;;;;N;;;;; @@ -15925,6 +15962,22 @@ FBBF;ARABIC SYMBOL RING;Sk;0;AL;;;;;N;;;;; FBC0;ARABIC SYMBOL SMALL TAH ABOVE;Sk;0;AL;;;;;N;;;;; FBC1;ARABIC SYMBOL SMALL TAH BELOW;Sk;0;AL;;;;;N;;;;; FBC2;ARABIC SYMBOL WASLA ABOVE;Sk;0;AL;;;;;N;;;;; +FBC3;ARABIC LIGATURE JALLA WA-ALAA;So;0;ON;;;;;N;;;;; +FBC4;ARABIC LIGATURE DAAMAT BARAKAATUHUM;So;0;ON;;;;;N;;;;; +FBC5;ARABIC LIGATURE RAHMATU ALLAAHI TAAALAA ALAYH;So;0;ON;;;;;N;;;;; +FBC6;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHIM;So;0;ON;;;;;N;;;;; +FBC7;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHIMAA;So;0;ON;;;;;N;;;;; +FBC8;ARABIC LIGATURE RAHIMAHUM ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;; +FBC9;ARABIC LIGATURE RAHIMAHUMAA ALLAAH;So;0;ON;;;;;N;;;;; +FBCA;ARABIC LIGATURE RAHIMAHUMAA ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;; +FBCB;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHUM;So;0;ON;;;;;N;;;;; +FBCC;ARABIC LIGATURE HAFIZAHU ALLAAH;So;0;ON;;;;;N;;;;; +FBCD;ARABIC LIGATURE HAFIZAHU ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;; +FBCE;ARABIC LIGATURE HAFIZAHUM ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;; +FBCF;ARABIC LIGATURE HAFIZAHUMAA ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;; +FBD0;ARABIC LIGATURE SALLALLAAHU TAAALAA ALAYHI WA-SALLAM;So;0;ON;;;;;N;;;;; +FBD1;ARABIC LIGATURE AJJAL ALLAAHU FARAJAHU ASH-SHAREEF;So;0;ON;;;;;N;;;;; +FBD2;ARABIC LIGATURE ALAYHI AR-RAHMAH;So;0;ON;;;;;N;;;;; FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL; 06AD;;;;N;;;;; FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL; 06AD;;;;N;;;;; FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL; 06AD;;;;N;;;;; @@ -16370,6 +16423,8 @@ FD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL; 0645 FD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062C 0645;;;;N;;;;; FD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL; 0645 062E 062C;;;;N;;;;; FD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062E 0645;;;;N;;;;; +FD90;ARABIC LIGATURE RAHMATU ALLAAHI ALAYH;So;0;ON;;;;;N;;;;; +FD91;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHAA;So;0;ON;;;;;N;;;;; FD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL; 0645 062C 062E;;;;N;;;;; FD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0647 0645 062C;;;;N;;;;; FD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0647 0645 0645;;;;N;;;;; @@ -16424,6 +16479,13 @@ FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0639 FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0635 0645 0645;;;;N;;;;; FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0633 062E 064A;;;;N;;;;; FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0646 062C 064A;;;;N;;;;; +FDC8;ARABIC LIGATURE RAHIMAHU ALLAAH TAAALAA;So;0;ON;;;;;N;;;;; +FDC9;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANH;So;0;ON;;;;;N;;;;; +FDCA;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHAA;So;0;ON;;;;;N;;;;; +FDCB;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHUMAA;So;0;ON;;;;;N;;;;; +FDCC;ARABIC LIGATURE SALLALLAHU ALAYHI WA-ALAA AALIHEE WA-SALLAM;So;0;ON;;;;;N;;;;; +FDCD;ARABIC LIGATURE AJJAL ALLAAHU TAAALAA FARAJAHU ASH-SHAREEF;So;0;ON;;;;;N;;;;; +FDCE;ARABIC LIGATURE KARRAMA ALLAAHU WAJHAH;So;0;ON;;;;;N;;;;; FDCF;ARABIC LIGATURE SALAAMUHU ALAYNAA;So;0;ON;;;;;N;;;;; FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0635 0644 06D2;;;;N;;;;; FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0642 0644 06D2;;;;N;;;;; @@ -18708,6 +18770,32 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10938;LYDIAN LETTER NN;Lo;0;R;;;;;N;;;;; 10939;LYDIAN LETTER C;Lo;0;R;;;;;N;;;;; 1093F;LYDIAN TRIANGULAR MARK;Po;0;R;;;;;N;;;;; +10940;SIDETIC LETTER N01;Lo;0;R;;;;;N;;;;; +10941;SIDETIC LETTER N02;Lo;0;R;;;;;N;;;;; +10942;SIDETIC LETTER N03;Lo;0;R;;;;;N;;;;; +10943;SIDETIC LETTER N04;Lo;0;R;;;;;N;;;;; +10944;SIDETIC LETTER N05;Lo;0;R;;;;;N;;;;; +10945;SIDETIC LETTER N06;Lo;0;R;;;;;N;;;;; +10946;SIDETIC LETTER N07;Lo;0;R;;;;;N;;;;; +10947;SIDETIC LETTER N08;Lo;0;R;;;;;N;;;;; +10948;SIDETIC LETTER N09;Lo;0;R;;;;;N;;;;; +10949;SIDETIC LETTER N10;Lo;0;R;;;;;N;;;;; +1094A;SIDETIC LETTER N11;Lo;0;R;;;;;N;;;;; +1094B;SIDETIC LETTER N12;Lo;0;R;;;;;N;;;;; +1094C;SIDETIC LETTER N13;Lo;0;R;;;;;N;;;;; +1094D;SIDETIC LETTER N14;Lo;0;R;;;;;N;;;;; +1094E;SIDETIC LETTER N15;Lo;0;R;;;;;N;;;;; +1094F;SIDETIC LETTER N16;Lo;0;R;;;;;N;;;;; +10950;SIDETIC LETTER N17;Lo;0;R;;;;;N;;;;; +10951;SIDETIC LETTER N18;Lo;0;R;;;;;N;;;;; +10952;SIDETIC LETTER N19;Lo;0;R;;;;;N;;;;; +10953;SIDETIC LETTER N20;Lo;0;R;;;;;N;;;;; +10954;SIDETIC LETTER N21;Lo;0;R;;;;;N;;;;; +10955;SIDETIC LETTER N22;Lo;0;R;;;;;N;;;;; +10956;SIDETIC LETTER N23;Lo;0;R;;;;;N;;;;; +10957;SIDETIC LETTER N24;Lo;0;R;;;;;N;;;;; +10958;SIDETIC LETTER N25;Lo;0;R;;;;;N;;;;; +10959;SIDETIC LETTER N26;Lo;0;R;;;;;N;;;;; 10980;MEROITIC HIEROGLYPHIC LETTER A;Lo;0;R;;;;;N;;;;; 10981;MEROITIC HIEROGLYPHIC LETTER E;Lo;0;R;;;;;N;;;;; 10982;MEROITIC HIEROGLYPHIC LETTER I;Lo;0;R;;;;;N;;;;; @@ -19541,6 +19629,20 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10EC2;ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;; 10EC3;ARABIC LETTER TAH WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;; 10EC4;ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;; +10EC5;ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW;Lm;0;AL;;;;;N;;;;; +10EC6;ARABIC LETTER THIN NOON;Lo;0;AL;;;;;N;;;;; +10EC7;ARABIC LETTER YEH WITH FOUR DOTS BELOW;Lo;0;AL;;;;;N;;;;; +10ED0;ARABIC BIBLICAL END OF VERSE;Po;0;ON;;;;;N;;;;; +10ED1;ARABIC LIGATURE ALAYHAA AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;; +10ED2;ARABIC LIGATURE ALAYHIM AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;; +10ED3;ARABIC LIGATURE ALAYHIMAA AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;; +10ED4;ARABIC LIGATURE QADDASA ALLAAHU SIRRAH;So;0;ON;;;;;N;;;;; +10ED5;ARABIC LIGATURE QUDDISA SIRRUHUM;So;0;ON;;;;;N;;;;; +10ED6;ARABIC LIGATURE QUDDISA SIRRUHUMAA;So;0;ON;;;;;N;;;;; +10ED7;ARABIC LIGATURE QUDDISAT ASRAARUHUM;So;0;ON;;;;;N;;;;; +10ED8;ARABIC LIGATURE NAWWARA ALLAAHU MARQADAH;So;0;ON;;;;;N;;;;; +10EFA;ARABIC DOUBLE VERTICAL BAR BELOW;Mn;220;NSM;;;;;N;;;;; +10EFB;ARABIC SMALL LOW NOON;Mn;220;NSM;;;;;N;;;;; 10EFC;ARABIC COMBINING ALEF OVERLAY;Mn;0;NSM;;;;;N;;;;; 10EFD;ARABIC SMALL LOW WORD SAKTA;Mn;220;NSM;;;;;N;;;;; 10EFE;ARABIC SMALL LOW WORD QASR;Mn;220;NSM;;;;;N;;;;; @@ -21521,6 +21623,14 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11B07;DEVANAGARI SIGN WESTERN NINE-LIKE BHALE;Po;0;L;;;;;N;;;;; 11B08;DEVANAGARI SIGN REVERSED NINE-LIKE BHALE;Po;0;L;;;;;N;;;;; 11B09;DEVANAGARI SIGN MINDU;Po;0;L;;;;;N;;;;; +11B60;SHARADA VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; +11B61;SHARADA VOWEL SIGN OOE;Mc;0;L;;;;;N;;;;; +11B62;SHARADA VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; +11B63;SHARADA VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;; +11B64;SHARADA VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;; +11B65;SHARADA VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;; +11B66;SHARADA VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; +11B67;SHARADA VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; 11BC0;SUNUWAR LETTER DEVI;Lo;0;L;;;;;N;;;;; 11BC1;SUNUWAR LETTER TASLA;Lo;0;L;;;;;N;;;;; 11BC2;SUNUWAR LETTER EKO;Lo;0;L;;;;;N;;;;; @@ -21868,6 +21978,60 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11DA7;GUNJALA GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 11DA8;GUNJALA GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 11DA9;GUNJALA GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11DB0;TOLONG SIKI LETTER I;Lo;0;L;;;;;N;;;;; +11DB1;TOLONG SIKI LETTER E;Lo;0;L;;;;;N;;;;; +11DB2;TOLONG SIKI LETTER U;Lo;0;L;;;;;N;;;;; +11DB3;TOLONG SIKI LETTER O;Lo;0;L;;;;;N;;;;; +11DB4;TOLONG SIKI LETTER A;Lo;0;L;;;;;N;;;;; +11DB5;TOLONG SIKI LETTER AA;Lo;0;L;;;;;N;;;;; +11DB6;TOLONG SIKI LETTER P;Lo;0;L;;;;;N;;;;; +11DB7;TOLONG SIKI LETTER PH;Lo;0;L;;;;;N;;;;; +11DB8;TOLONG SIKI LETTER B;Lo;0;L;;;;;N;;;;; +11DB9;TOLONG SIKI LETTER BH;Lo;0;L;;;;;N;;;;; +11DBA;TOLONG SIKI LETTER M;Lo;0;L;;;;;N;;;;; +11DBB;TOLONG SIKI LETTER T;Lo;0;L;;;;;N;;;;; +11DBC;TOLONG SIKI LETTER TH;Lo;0;L;;;;;N;;;;; +11DBD;TOLONG SIKI LETTER D;Lo;0;L;;;;;N;;;;; +11DBE;TOLONG SIKI LETTER DH;Lo;0;L;;;;;N;;;;; +11DBF;TOLONG SIKI LETTER N;Lo;0;L;;;;;N;;;;; +11DC0;TOLONG SIKI LETTER TT;Lo;0;L;;;;;N;;;;; +11DC1;TOLONG SIKI LETTER TTH;Lo;0;L;;;;;N;;;;; +11DC2;TOLONG SIKI LETTER DD;Lo;0;L;;;;;N;;;;; +11DC3;TOLONG SIKI LETTER DDH;Lo;0;L;;;;;N;;;;; +11DC4;TOLONG SIKI LETTER NN;Lo;0;L;;;;;N;;;;; +11DC5;TOLONG SIKI LETTER C;Lo;0;L;;;;;N;;;;; +11DC6;TOLONG SIKI LETTER CH;Lo;0;L;;;;;N;;;;; +11DC7;TOLONG SIKI LETTER J;Lo;0;L;;;;;N;;;;; +11DC8;TOLONG SIKI LETTER JH;Lo;0;L;;;;;N;;;;; +11DC9;TOLONG SIKI LETTER NY;Lo;0;L;;;;;N;;;;; +11DCA;TOLONG SIKI LETTER K;Lo;0;L;;;;;N;;;;; +11DCB;TOLONG SIKI LETTER KH;Lo;0;L;;;;;N;;;;; +11DCC;TOLONG SIKI LETTER G;Lo;0;L;;;;;N;;;;; +11DCD;TOLONG SIKI LETTER GH;Lo;0;L;;;;;N;;;;; +11DCE;TOLONG SIKI LETTER NG;Lo;0;L;;;;;N;;;;; +11DCF;TOLONG SIKI LETTER Y;Lo;0;L;;;;;N;;;;; +11DD0;TOLONG SIKI LETTER R;Lo;0;L;;;;;N;;;;; +11DD1;TOLONG SIKI LETTER L;Lo;0;L;;;;;N;;;;; +11DD2;TOLONG SIKI LETTER V;Lo;0;L;;;;;N;;;;; +11DD3;TOLONG SIKI LETTER NNY;Lo;0;L;;;;;N;;;;; +11DD4;TOLONG SIKI LETTER S;Lo;0;L;;;;;N;;;;; +11DD5;TOLONG SIKI LETTER H;Lo;0;L;;;;;N;;;;; +11DD6;TOLONG SIKI LETTER X;Lo;0;L;;;;;N;;;;; +11DD7;TOLONG SIKI LETTER RR;Lo;0;L;;;;;N;;;;; +11DD8;TOLONG SIKI LETTER RRH;Lo;0;L;;;;;N;;;;; +11DD9;TOLONG SIKI SIGN SELA;Lm;0;L;;;;;N;;;;; +11DDA;TOLONG SIKI SIGN HECAKA;Lo;0;L;;;;;N;;;;; +11DDB;TOLONG SIKI UNGGA;Lo;0;L;;;;;N;;;;; +11DE0;TOLONG SIKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11DE1;TOLONG SIKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11DE2;TOLONG SIKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11DE3;TOLONG SIKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11DE4;TOLONG SIKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11DE5;TOLONG SIKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11DE6;TOLONG SIKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11DE7;TOLONG SIKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11DE8;TOLONG SIKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11DE9;TOLONG SIKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 11EE0;MAKASAR LETTER KA;Lo;0;L;;;;;N;;;;; 11EE1;MAKASAR LETTER GA;Lo;0;L;;;;;N;;;;; 11EE2;MAKASAR LETTER NGA;Lo;0;L;;;;;N;;;;; @@ -22088,8 +22252,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 12035;CUNEIFORM SIGN ARAD TIMES KUR;Lo;0;L;;;;;N;;;;; 12036;CUNEIFORM SIGN ARKAB;Lo;0;L;;;;;N;;;;; 12037;CUNEIFORM SIGN ASAL2;Lo;0;L;;;;;N;;;;; -12038;CUNEIFORM SIGN ASH;Lo;0;L;;;;;N;;;;; -12039;CUNEIFORM SIGN ASH ZIDA TENU;Lo;0;L;;;;;N;;;;; +12038;CUNEIFORM SIGN ASH;Lo;0;L;;;;1;N;;;;; +12039;CUNEIFORM SIGN ASH ZIDA TENU;Lo;0;L;;;;1;N;;;;; 1203A;CUNEIFORM SIGN ASH KABA TENU;Lo;0;L;;;;;N;;;;; 1203B;CUNEIFORM SIGN ASH OVER ASH TUG2 OVER TUG2 TUG2 OVER TUG2 PAP;Lo;0;L;;;;;N;;;;; 1203C;CUNEIFORM SIGN ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;; @@ -22153,7 +22317,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 12076;CUNEIFORM SIGN DIM2;Lo;0;L;;;;;N;;;;; 12077;CUNEIFORM SIGN DIN;Lo;0;L;;;;;N;;;;; 12078;CUNEIFORM SIGN DIN KASKAL U GUNU DISH;Lo;0;L;;;;;N;;;;; -12079;CUNEIFORM SIGN DISH;Lo;0;L;;;;;N;;;;; +12079;CUNEIFORM SIGN DISH;Lo;0;L;;;;1;N;;;;; 1207A;CUNEIFORM SIGN DU;Lo;0;L;;;;;N;;;;; 1207B;CUNEIFORM SIGN DU OVER DU;Lo;0;L;;;;;N;;;;; 1207C;CUNEIFORM SIGN DU GUNU;Lo;0;L;;;;;N;;;;; @@ -22582,12 +22746,12 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 12223;CUNEIFORM SIGN MA2;Lo;0;L;;;;;N;;;;; 12224;CUNEIFORM SIGN MAH;Lo;0;L;;;;;N;;;;; 12225;CUNEIFORM SIGN MAR;Lo;0;L;;;;;N;;;;; -12226;CUNEIFORM SIGN MASH;Lo;0;L;;;;;N;;;;; +12226;CUNEIFORM SIGN MASH;Lo;0;L;;;;1/2;N;;;;; 12227;CUNEIFORM SIGN MASH2;Lo;0;L;;;;;N;;;;; 12228;CUNEIFORM SIGN ME;Lo;0;L;;;;;N;;;;; 12229;CUNEIFORM SIGN MES;Lo;0;L;;;;;N;;;;; 1222A;CUNEIFORM SIGN MI;Lo;0;L;;;;;N;;;;; -1222B;CUNEIFORM SIGN MIN;Lo;0;L;;;;;N;;;;; +1222B;CUNEIFORM SIGN MIN;Lo;0;L;;;;2;N;;;;; 1222C;CUNEIFORM SIGN MU;Lo;0;L;;;;;N;;;;; 1222D;CUNEIFORM SIGN MU OVER MU;Lo;0;L;;;;;N;;;;; 1222E;CUNEIFORM SIGN MUG;Lo;0;L;;;;;N;;;;; @@ -22811,9 +22975,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 12308;CUNEIFORM SIGN TUM;Lo;0;L;;;;;N;;;;; 12309;CUNEIFORM SIGN TUR;Lo;0;L;;;;;N;;;;; 1230A;CUNEIFORM SIGN TUR OVER TUR ZA OVER ZA;Lo;0;L;;;;;N;;;;; -1230B;CUNEIFORM SIGN U;Lo;0;L;;;;;N;;;;; +1230B;CUNEIFORM SIGN U;Lo;0;L;;;;1;N;;;;; 1230C;CUNEIFORM SIGN U GUD;Lo;0;L;;;;;N;;;;; -1230D;CUNEIFORM SIGN U U U;Lo;0;L;;;;;N;;;;; +1230D;CUNEIFORM SIGN U U U;Lo;0;L;;;;3;N;;;;; 1230E;CUNEIFORM SIGN U OVER U PA OVER PA GAR OVER GAR;Lo;0;L;;;;;N;;;;; 1230F;CUNEIFORM SIGN U OVER U SUR OVER SUR;Lo;0;L;;;;;N;;;;; 12310;CUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSED;Lo;0;L;;;;;N;;;;; @@ -22953,7 +23117,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 12396;CUNEIFORM SIGN SAG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;; 12397;CUNEIFORM SIGN TI2;Lo;0;L;;;;;N;;;;; 12398;CUNEIFORM SIGN UM TIMES ME;Lo;0;L;;;;;N;;;;; -12399;CUNEIFORM SIGN U U;Lo;0;L;;;;;N;;;;; +12399;CUNEIFORM SIGN U U;Lo;0;L;;;;2;N;;;;; 12400;CUNEIFORM NUMERIC SIGN TWO ASH;Nl;0;L;;;;2;N;;;;; 12401;CUNEIFORM NUMERIC SIGN THREE ASH;Nl;0;L;;;;3;N;;;;; 12402;CUNEIFORM NUMERIC SIGN FOUR ASH;Nl;0;L;;;;4;N;;;;; @@ -30124,6 +30288,56 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 16E98;MEDEFAIDRIN FULL STOP;Po;0;L;;;;;N;;;;; 16E99;MEDEFAIDRIN SYMBOL AIVA;Po;0;L;;;;;N;;;;; 16E9A;MEDEFAIDRIN EXCLAMATION OH;Po;0;L;;;;;N;;;;; +16EA0;BERIA ERFE CAPITAL LETTER ARKAB;Lu;0;L;;;;;N;;;;16EBB; +16EA1;BERIA ERFE CAPITAL LETTER BASIGNA;Lu;0;L;;;;;N;;;;16EBC; +16EA2;BERIA ERFE CAPITAL LETTER DARBAI;Lu;0;L;;;;;N;;;;16EBD; +16EA3;BERIA ERFE CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;16EBE; +16EA4;BERIA ERFE CAPITAL LETTER FITKO;Lu;0;L;;;;;N;;;;16EBF; +16EA5;BERIA ERFE CAPITAL LETTER GOWAY;Lu;0;L;;;;;N;;;;16EC0; +16EA6;BERIA ERFE CAPITAL LETTER HIRDEABO;Lu;0;L;;;;;N;;;;16EC1; +16EA7;BERIA ERFE CAPITAL LETTER I;Lu;0;L;;;;;N;;;;16EC2; +16EA8;BERIA ERFE CAPITAL LETTER DJAI;Lu;0;L;;;;;N;;;;16EC3; +16EA9;BERIA ERFE CAPITAL LETTER KOBO;Lu;0;L;;;;;N;;;;16EC4; +16EAA;BERIA ERFE CAPITAL LETTER LAKKO;Lu;0;L;;;;;N;;;;16EC5; +16EAB;BERIA ERFE CAPITAL LETTER MERI;Lu;0;L;;;;;N;;;;16EC6; +16EAC;BERIA ERFE CAPITAL LETTER NINI;Lu;0;L;;;;;N;;;;16EC7; +16EAD;BERIA ERFE CAPITAL LETTER GNA;Lu;0;L;;;;;N;;;;16EC8; +16EAE;BERIA ERFE CAPITAL LETTER NGAY;Lu;0;L;;;;;N;;;;16EC9; +16EAF;BERIA ERFE CAPITAL LETTER OI;Lu;0;L;;;;;N;;;;16ECA; +16EB0;BERIA ERFE CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;16ECB; +16EB1;BERIA ERFE CAPITAL LETTER ERIGO;Lu;0;L;;;;;N;;;;16ECC; +16EB2;BERIA ERFE CAPITAL LETTER ERIGO TAMURA;Lu;0;L;;;;;N;;;;16ECD; +16EB3;BERIA ERFE CAPITAL LETTER SERI;Lu;0;L;;;;;N;;;;16ECE; +16EB4;BERIA ERFE CAPITAL LETTER SHEP;Lu;0;L;;;;;N;;;;16ECF; +16EB5;BERIA ERFE CAPITAL LETTER TATASOUE;Lu;0;L;;;;;N;;;;16ED0; +16EB6;BERIA ERFE CAPITAL LETTER UI;Lu;0;L;;;;;N;;;;16ED1; +16EB7;BERIA ERFE CAPITAL LETTER WASSE;Lu;0;L;;;;;N;;;;16ED2; +16EB8;BERIA ERFE CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;16ED3; +16EBB;BERIA ERFE SMALL LETTER ARKAB;Ll;0;L;;;;;N;;;16EA0;;16EA0 +16EBC;BERIA ERFE SMALL LETTER BASIGNA;Ll;0;L;;;;;N;;;16EA1;;16EA1 +16EBD;BERIA ERFE SMALL LETTER DARBAI;Ll;0;L;;;;;N;;;16EA2;;16EA2 +16EBE;BERIA ERFE SMALL LETTER EH;Ll;0;L;;;;;N;;;16EA3;;16EA3 +16EBF;BERIA ERFE SMALL LETTER FITKO;Ll;0;L;;;;;N;;;16EA4;;16EA4 +16EC0;BERIA ERFE SMALL LETTER GOWAY;Ll;0;L;;;;;N;;;16EA5;;16EA5 +16EC1;BERIA ERFE SMALL LETTER HIRDEABO;Ll;0;L;;;;;N;;;16EA6;;16EA6 +16EC2;BERIA ERFE SMALL LETTER I;Ll;0;L;;;;;N;;;16EA7;;16EA7 +16EC3;BERIA ERFE SMALL LETTER DJAI;Ll;0;L;;;;;N;;;16EA8;;16EA8 +16EC4;BERIA ERFE SMALL LETTER KOBO;Ll;0;L;;;;;N;;;16EA9;;16EA9 +16EC5;BERIA ERFE SMALL LETTER LAKKO;Ll;0;L;;;;;N;;;16EAA;;16EAA +16EC6;BERIA ERFE SMALL LETTER MERI;Ll;0;L;;;;;N;;;16EAB;;16EAB +16EC7;BERIA ERFE SMALL LETTER NINI;Ll;0;L;;;;;N;;;16EAC;;16EAC +16EC8;BERIA ERFE SMALL LETTER GNA;Ll;0;L;;;;;N;;;16EAD;;16EAD +16EC9;BERIA ERFE SMALL LETTER NGAY;Ll;0;L;;;;;N;;;16EAE;;16EAE +16ECA;BERIA ERFE SMALL LETTER OI;Ll;0;L;;;;;N;;;16EAF;;16EAF +16ECB;BERIA ERFE SMALL LETTER PI;Ll;0;L;;;;;N;;;16EB0;;16EB0 +16ECC;BERIA ERFE SMALL LETTER ERIGO;Ll;0;L;;;;;N;;;16EB1;;16EB1 +16ECD;BERIA ERFE SMALL LETTER ERIGO TAMURA;Ll;0;L;;;;;N;;;16EB2;;16EB2 +16ECE;BERIA ERFE SMALL LETTER SERI;Ll;0;L;;;;;N;;;16EB3;;16EB3 +16ECF;BERIA ERFE SMALL LETTER SHEP;Ll;0;L;;;;;N;;;16EB4;;16EB4 +16ED0;BERIA ERFE SMALL LETTER TATASOUE;Ll;0;L;;;;;N;;;16EB5;;16EB5 +16ED1;BERIA ERFE SMALL LETTER UI;Ll;0;L;;;;;N;;;16EB6;;16EB6 +16ED2;BERIA ERFE SMALL LETTER WASSE;Ll;0;L;;;;;N;;;16EB7;;16EB7 +16ED3;BERIA ERFE SMALL LETTER AY;Ll;0;L;;;;;N;;;16EB8;;16EB8 16F00;MIAO LETTER PA;Lo;0;L;;;;;N;;;;; 16F01;MIAO LETTER BA;Lo;0;L;;;;;N;;;;; 16F02;MIAO LETTER YI PA;Lo;0;L;;;;;N;;;;; @@ -30280,8 +30494,13 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 16FE4;KHITAN SMALL SCRIPT FILLER;Mn;0;NSM;;;;;N;;;;; 16FF0;VIETNAMESE ALTERNATE READING MARK CA;Mc;6;L;;;;;N;;;;; 16FF1;VIETNAMESE ALTERNATE READING MARK NHAY;Mc;6;L;;;;;N;;;;; +16FF2;CHINESE SMALL SIMPLIFIED ER;Lm;0;L;;;;;N;;;;; +16FF3;CHINESE SMALL TRADITIONAL ER;Lm;0;L;;;;;N;;;;; +16FF4;YANGQIN SIGN SLOW ONE BEAT;Nl;0;L;;;;1;N;;;;; +16FF5;YANGQIN SIGN SLOW THREE HALF BEATS;Nl;0;L;;;;3/2;N;;;;; +16FF6;YANGQIN SIGN SLOW TWO BEATS;Nl;0;L;;;;2;N;;;;; 17000;;Lo;0;L;;;;;N;;;;; -187F7;;Lo;0;L;;;;;N;;;;; +187FF;;Lo;0;L;;;;;N;;;;; 18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;; 18801;TANGUT COMPONENT-002;Lo;0;L;;;;;N;;;;; 18802;TANGUT COMPONENT-003;Lo;0;L;;;;;N;;;;; @@ -31522,7 +31741,122 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 18CD5;KHITAN SMALL SCRIPT CHARACTER-18CD5;Lo;0;L;;;;;N;;;;; 18CFF;KHITAN SMALL SCRIPT CHARACTER-18CFF;Lo;0;L;;;;;N;;;;; 18D00;;Lo;0;L;;;;;N;;;;; -18D08;;Lo;0;L;;;;;N;;;;; +18D1E;;Lo;0;L;;;;;N;;;;; +18D80;TANGUT COMPONENT-769;Lo;0;L;;;;;N;;;;; +18D81;TANGUT COMPONENT-770;Lo;0;L;;;;;N;;;;; +18D82;TANGUT COMPONENT-771;Lo;0;L;;;;;N;;;;; +18D83;TANGUT COMPONENT-772;Lo;0;L;;;;;N;;;;; +18D84;TANGUT COMPONENT-773;Lo;0;L;;;;;N;;;;; +18D85;TANGUT COMPONENT-774;Lo;0;L;;;;;N;;;;; +18D86;TANGUT COMPONENT-775;Lo;0;L;;;;;N;;;;; +18D87;TANGUT COMPONENT-776;Lo;0;L;;;;;N;;;;; +18D88;TANGUT COMPONENT-777;Lo;0;L;;;;;N;;;;; +18D89;TANGUT COMPONENT-778;Lo;0;L;;;;;N;;;;; +18D8A;TANGUT COMPONENT-779;Lo;0;L;;;;;N;;;;; +18D8B;TANGUT COMPONENT-780;Lo;0;L;;;;;N;;;;; +18D8C;TANGUT COMPONENT-781;Lo;0;L;;;;;N;;;;; +18D8D;TANGUT COMPONENT-782;Lo;0;L;;;;;N;;;;; +18D8E;TANGUT COMPONENT-783;Lo;0;L;;;;;N;;;;; +18D8F;TANGUT COMPONENT-784;Lo;0;L;;;;;N;;;;; +18D90;TANGUT COMPONENT-785;Lo;0;L;;;;;N;;;;; +18D91;TANGUT COMPONENT-786;Lo;0;L;;;;;N;;;;; +18D92;TANGUT COMPONENT-787;Lo;0;L;;;;;N;;;;; +18D93;TANGUT COMPONENT-788;Lo;0;L;;;;;N;;;;; +18D94;TANGUT COMPONENT-789;Lo;0;L;;;;;N;;;;; +18D95;TANGUT COMPONENT-790;Lo;0;L;;;;;N;;;;; +18D96;TANGUT COMPONENT-791;Lo;0;L;;;;;N;;;;; +18D97;TANGUT COMPONENT-792;Lo;0;L;;;;;N;;;;; +18D98;TANGUT COMPONENT-793;Lo;0;L;;;;;N;;;;; +18D99;TANGUT COMPONENT-794;Lo;0;L;;;;;N;;;;; +18D9A;TANGUT COMPONENT-795;Lo;0;L;;;;;N;;;;; +18D9B;TANGUT COMPONENT-796;Lo;0;L;;;;;N;;;;; +18D9C;TANGUT COMPONENT-797;Lo;0;L;;;;;N;;;;; +18D9D;TANGUT COMPONENT-798;Lo;0;L;;;;;N;;;;; +18D9E;TANGUT COMPONENT-799;Lo;0;L;;;;;N;;;;; +18D9F;TANGUT COMPONENT-800;Lo;0;L;;;;;N;;;;; +18DA0;TANGUT COMPONENT-801;Lo;0;L;;;;;N;;;;; +18DA1;TANGUT COMPONENT-802;Lo;0;L;;;;;N;;;;; +18DA2;TANGUT COMPONENT-803;Lo;0;L;;;;;N;;;;; +18DA3;TANGUT COMPONENT-804;Lo;0;L;;;;;N;;;;; +18DA4;TANGUT COMPONENT-805;Lo;0;L;;;;;N;;;;; +18DA5;TANGUT COMPONENT-806;Lo;0;L;;;;;N;;;;; +18DA6;TANGUT COMPONENT-807;Lo;0;L;;;;;N;;;;; +18DA7;TANGUT COMPONENT-808;Lo;0;L;;;;;N;;;;; +18DA8;TANGUT COMPONENT-809;Lo;0;L;;;;;N;;;;; +18DA9;TANGUT COMPONENT-810;Lo;0;L;;;;;N;;;;; +18DAA;TANGUT COMPONENT-811;Lo;0;L;;;;;N;;;;; +18DAB;TANGUT COMPONENT-812;Lo;0;L;;;;;N;;;;; +18DAC;TANGUT COMPONENT-813;Lo;0;L;;;;;N;;;;; +18DAD;TANGUT COMPONENT-814;Lo;0;L;;;;;N;;;;; +18DAE;TANGUT COMPONENT-815;Lo;0;L;;;;;N;;;;; +18DAF;TANGUT COMPONENT-816;Lo;0;L;;;;;N;;;;; +18DB0;TANGUT COMPONENT-817;Lo;0;L;;;;;N;;;;; +18DB1;TANGUT COMPONENT-818;Lo;0;L;;;;;N;;;;; +18DB2;TANGUT COMPONENT-819;Lo;0;L;;;;;N;;;;; +18DB3;TANGUT COMPONENT-820;Lo;0;L;;;;;N;;;;; +18DB4;TANGUT COMPONENT-821;Lo;0;L;;;;;N;;;;; +18DB5;TANGUT COMPONENT-822;Lo;0;L;;;;;N;;;;; +18DB6;TANGUT COMPONENT-823;Lo;0;L;;;;;N;;;;; +18DB7;TANGUT COMPONENT-824;Lo;0;L;;;;;N;;;;; +18DB8;TANGUT COMPONENT-825;Lo;0;L;;;;;N;;;;; +18DB9;TANGUT COMPONENT-826;Lo;0;L;;;;;N;;;;; +18DBA;TANGUT COMPONENT-827;Lo;0;L;;;;;N;;;;; +18DBB;TANGUT COMPONENT-828;Lo;0;L;;;;;N;;;;; +18DBC;TANGUT COMPONENT-829;Lo;0;L;;;;;N;;;;; +18DBD;TANGUT COMPONENT-830;Lo;0;L;;;;;N;;;;; +18DBE;TANGUT COMPONENT-831;Lo;0;L;;;;;N;;;;; +18DBF;TANGUT COMPONENT-832;Lo;0;L;;;;;N;;;;; +18DC0;TANGUT COMPONENT-833;Lo;0;L;;;;;N;;;;; +18DC1;TANGUT COMPONENT-834;Lo;0;L;;;;;N;;;;; +18DC2;TANGUT COMPONENT-835;Lo;0;L;;;;;N;;;;; +18DC3;TANGUT COMPONENT-836;Lo;0;L;;;;;N;;;;; +18DC4;TANGUT COMPONENT-837;Lo;0;L;;;;;N;;;;; +18DC5;TANGUT COMPONENT-838;Lo;0;L;;;;;N;;;;; +18DC6;TANGUT COMPONENT-839;Lo;0;L;;;;;N;;;;; +18DC7;TANGUT COMPONENT-840;Lo;0;L;;;;;N;;;;; +18DC8;TANGUT COMPONENT-841;Lo;0;L;;;;;N;;;;; +18DC9;TANGUT COMPONENT-842;Lo;0;L;;;;;N;;;;; +18DCA;TANGUT COMPONENT-843;Lo;0;L;;;;;N;;;;; +18DCB;TANGUT COMPONENT-844;Lo;0;L;;;;;N;;;;; +18DCC;TANGUT COMPONENT-845;Lo;0;L;;;;;N;;;;; +18DCD;TANGUT COMPONENT-846;Lo;0;L;;;;;N;;;;; +18DCE;TANGUT COMPONENT-847;Lo;0;L;;;;;N;;;;; +18DCF;TANGUT COMPONENT-848;Lo;0;L;;;;;N;;;;; +18DD0;TANGUT COMPONENT-849;Lo;0;L;;;;;N;;;;; +18DD1;TANGUT COMPONENT-850;Lo;0;L;;;;;N;;;;; +18DD2;TANGUT COMPONENT-851;Lo;0;L;;;;;N;;;;; +18DD3;TANGUT COMPONENT-852;Lo;0;L;;;;;N;;;;; +18DD4;TANGUT COMPONENT-853;Lo;0;L;;;;;N;;;;; +18DD5;TANGUT COMPONENT-854;Lo;0;L;;;;;N;;;;; +18DD6;TANGUT COMPONENT-855;Lo;0;L;;;;;N;;;;; +18DD7;TANGUT COMPONENT-856;Lo;0;L;;;;;N;;;;; +18DD8;TANGUT COMPONENT-857;Lo;0;L;;;;;N;;;;; +18DD9;TANGUT COMPONENT-858;Lo;0;L;;;;;N;;;;; +18DDA;TANGUT COMPONENT-859;Lo;0;L;;;;;N;;;;; +18DDB;TANGUT COMPONENT-860;Lo;0;L;;;;;N;;;;; +18DDC;TANGUT COMPONENT-861;Lo;0;L;;;;;N;;;;; +18DDD;TANGUT COMPONENT-862;Lo;0;L;;;;;N;;;;; +18DDE;TANGUT COMPONENT-863;Lo;0;L;;;;;N;;;;; +18DDF;TANGUT COMPONENT-864;Lo;0;L;;;;;N;;;;; +18DE0;TANGUT COMPONENT-865;Lo;0;L;;;;;N;;;;; +18DE1;TANGUT COMPONENT-866;Lo;0;L;;;;;N;;;;; +18DE2;TANGUT COMPONENT-867;Lo;0;L;;;;;N;;;;; +18DE3;TANGUT COMPONENT-868;Lo;0;L;;;;;N;;;;; +18DE4;TANGUT COMPONENT-869;Lo;0;L;;;;;N;;;;; +18DE5;TANGUT COMPONENT-870;Lo;0;L;;;;;N;;;;; +18DE6;TANGUT COMPONENT-871;Lo;0;L;;;;;N;;;;; +18DE7;TANGUT COMPONENT-872;Lo;0;L;;;;;N;;;;; +18DE8;TANGUT COMPONENT-873;Lo;0;L;;;;;N;;;;; +18DE9;TANGUT COMPONENT-874;Lo;0;L;;;;;N;;;;; +18DEA;TANGUT COMPONENT-875;Lo;0;L;;;;;N;;;;; +18DEB;TANGUT COMPONENT-876;Lo;0;L;;;;;N;;;;; +18DEC;TANGUT COMPONENT-877;Lo;0;L;;;;;N;;;;; +18DED;TANGUT COMPONENT-878;Lo;0;L;;;;;N;;;;; +18DEE;TANGUT COMPONENT-879;Lo;0;L;;;;;N;;;;; +18DEF;TANGUT COMPONENT-880;Lo;0;L;;;;;N;;;;; +18DF0;TANGUT COMPONENT-881;Lo;0;L;;;;;N;;;;; +18DF1;TANGUT COMPONENT-882;Lo;0;L;;;;;N;;;;; +18DF2;TANGUT COMPONENT-883;Lo;0;L;;;;;N;;;;; 1AFF0;KATAKANA LETTER MINNAN TONE-2;Lm;0;L;;;;;N;;;;; 1AFF1;KATAKANA LETTER MINNAN TONE-3;Lm;0;L;;;;;N;;;;; 1AFF2;KATAKANA LETTER MINNAN TONE-4;Lm;0;L;;;;;N;;;;; @@ -32629,6 +32963,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1CCF7;OUTLINED DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; 1CCF8;OUTLINED DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; 1CCF9;OUTLINED DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1CCFA;SNAKE SYMBOL;So;0;ON;;;;;N;;;;; +1CCFB;FLYING SAUCER SYMBOL;So;0;ON;;;;;N;;;;; +1CCFC;NOSE SYMBOL;So;0;ON;;;;;N;;;;; 1CD00;BLOCK OCTANT-3;So;0;ON;;;;;N;;;;; 1CD01;BLOCK OCTANT-23;So;0;ON;;;;;N;;;;; 1CD02;BLOCK OCTANT-123;So;0;ON;;;;;N;;;;; @@ -33065,6 +33402,46 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1CEB1;KEYHOLE;So;0;ON;;;;;N;;;;; 1CEB2;OLD PERSONAL COMPUTER WITH MONITOR IN PORTRAIT ORIENTATION;So;0;ON;;;;;N;;;;; 1CEB3;BLACK RIGHT TRIANGLE CARET;So;0;ON;;;;;N;;;;; +1CEBA;FRAGILE SYMBOL;So;0;ON;;;;;N;;;;; +1CEBB;OFFICE BUILDING SYMBOL;So;0;ON;;;;;N;;;;; +1CEBC;TREE SYMBOL;So;0;ON;;;;;N;;;;; +1CEBD;APPLE SYMBOL;So;0;ON;;;;;N;;;;; +1CEBE;CHERRY SYMBOL;So;0;ON;;;;;N;;;;; +1CEBF;STRAWBERRY SYMBOL;So;0;ON;;;;;N;;;;; +1CEC0;HEBE;So;0;ON;;;;;N;;;;; +1CEC1;IRIS;So;0;ON;;;;;N;;;;; +1CEC2;FLORA;So;0;ON;;;;;N;;;;; +1CEC3;METIS;So;0;ON;;;;;N;;;;; +1CEC4;PARTHENOPE;So;0;ON;;;;;N;;;;; +1CEC5;VICTORIA;So;0;ON;;;;;N;;;;; +1CEC6;EGERIA;So;0;ON;;;;;N;;;;; +1CEC7;IRENE;So;0;ON;;;;;N;;;;; +1CEC8;EUNOMIA;So;0;ON;;;;;N;;;;; +1CEC9;PSYCHE;So;0;ON;;;;;N;;;;; +1CECA;THETIS;So;0;ON;;;;;N;;;;; +1CECB;MELPOMENE;So;0;ON;;;;;N;;;;; +1CECC;FORTUNA;So;0;ON;;;;;N;;;;; +1CECD;ASTRONOMICAL SYMBOL FOR ASTEROID PROSERPINA;So;0;ON;;;;;N;;;;; +1CECE;BELLONA;So;0;ON;;;;;N;;;;; +1CECF;AMPHITRITE;So;0;ON;;;;;N;;;;; +1CED0;LEUKOTHEA;So;0;ON;;;;;N;;;;; +1CEE0;GEOMANTIC FIGURE POPULUS;So;0;ON;;;;;N;;;;; +1CEE1;GEOMANTIC FIGURE TRISTITIA;So;0;ON;;;;;N;;;;; +1CEE2;GEOMANTIC FIGURE ALBUS;So;0;ON;;;;;N;;;;; +1CEE3;GEOMANTIC FIGURE FORTUNA MAJOR;So;0;ON;;;;;N;;;;; +1CEE4;GEOMANTIC FIGURE RUBEUS;So;0;ON;;;;;N;;;;; +1CEE5;GEOMANTIC FIGURE ACQUISITIO;So;0;ON;;;;;N;;;;; +1CEE6;GEOMANTIC FIGURE CONJUNCTIO;So;0;ON;;;;;N;;;;; +1CEE7;GEOMANTIC FIGURE CAPUT DRACONIS;So;0;ON;;;;;N;;;;; +1CEE8;GEOMANTIC FIGURE LAETITIA;So;0;ON;;;;;N;;;;; +1CEE9;GEOMANTIC FIGURE CARCER;So;0;ON;;;;;N;;;;; +1CEEA;GEOMANTIC FIGURE AMISSIO;So;0;ON;;;;;N;;;;; +1CEEB;GEOMANTIC FIGURE PUELLA;So;0;ON;;;;;N;;;;; +1CEEC;GEOMANTIC FIGURE FORTUNA MINOR;So;0;ON;;;;;N;;;;; +1CEED;GEOMANTIC FIGURE PUER;So;0;ON;;;;;N;;;;; +1CEEE;GEOMANTIC FIGURE CAUDA DRACONIS;So;0;ON;;;;;N;;;;; +1CEEF;GEOMANTIC FIGURE VIA;So;0;ON;;;;;N;;;;; +1CEF0;MEDIUM SMALL WHITE CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;; 1CF00;ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;; 1CF01;ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;; 1CF02;ZNAMENNY COMBINING MARK TSATA ON LEFT;Mn;0;NSM;;;;;N;;;;; @@ -36004,6 +36381,61 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1E5F9;OL ONAL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 1E5FA;OL ONAL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 1E5FF;OL ONAL ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +1E6C0;TAI YO LETTER LOW KO;Lo;0;L;;;;;N;;;;; +1E6C1;TAI YO LETTER HIGH KO;Lo;0;L;;;;;N;;;;; +1E6C2;TAI YO LETTER LOW KHO;Lo;0;L;;;;;N;;;;; +1E6C3;TAI YO LETTER HIGH KHO;Lo;0;L;;;;;N;;;;; +1E6C4;TAI YO LETTER GO;Lo;0;L;;;;;N;;;;; +1E6C5;TAI YO LETTER NGO;Lo;0;L;;;;;N;;;;; +1E6C6;TAI YO LETTER CO;Lo;0;L;;;;;N;;;;; +1E6C7;TAI YO LETTER LOW XO;Lo;0;L;;;;;N;;;;; +1E6C8;TAI YO LETTER HIGH XO;Lo;0;L;;;;;N;;;;; +1E6C9;TAI YO LETTER LOW NYO;Lo;0;L;;;;;N;;;;; +1E6CA;TAI YO LETTER HIGH NYO;Lo;0;L;;;;;N;;;;; +1E6CB;TAI YO LETTER DO;Lo;0;L;;;;;N;;;;; +1E6CC;TAI YO LETTER LOW TO;Lo;0;L;;;;;N;;;;; +1E6CD;TAI YO LETTER HIGH TO;Lo;0;L;;;;;N;;;;; +1E6CE;TAI YO LETTER THO;Lo;0;L;;;;;N;;;;; +1E6CF;TAI YO LETTER NO;Lo;0;L;;;;;N;;;;; +1E6D0;TAI YO LETTER BO;Lo;0;L;;;;;N;;;;; +1E6D1;TAI YO LETTER LOW PO;Lo;0;L;;;;;N;;;;; +1E6D2;TAI YO LETTER HIGH PO;Lo;0;L;;;;;N;;;;; +1E6D3;TAI YO LETTER PHO;Lo;0;L;;;;;N;;;;; +1E6D4;TAI YO LETTER LOW FO;Lo;0;L;;;;;N;;;;; +1E6D5;TAI YO LETTER HIGH FO;Lo;0;L;;;;;N;;;;; +1E6D6;TAI YO LETTER MO;Lo;0;L;;;;;N;;;;; +1E6D7;TAI YO LETTER YO;Lo;0;L;;;;;N;;;;; +1E6D8;TAI YO LETTER LO;Lo;0;L;;;;;N;;;;; +1E6D9;TAI YO LETTER VO;Lo;0;L;;;;;N;;;;; +1E6DA;TAI YO LETTER LOW HO;Lo;0;L;;;;;N;;;;; +1E6DB;TAI YO LETTER HIGH HO;Lo;0;L;;;;;N;;;;; +1E6DC;TAI YO LETTER QO;Lo;0;L;;;;;N;;;;; +1E6DD;TAI YO LETTER LOW KVO;Lo;0;L;;;;;N;;;;; +1E6DE;TAI YO LETTER HIGH KVO;Lo;0;L;;;;;N;;;;; +1E6E0;TAI YO LETTER AA;Lo;0;L;;;;;N;;;;; +1E6E1;TAI YO LETTER I;Lo;0;L;;;;;N;;;;; +1E6E2;TAI YO LETTER UE;Lo;0;L;;;;;N;;;;; +1E6E3;TAI YO SIGN UE;Mn;230;NSM;;;;;N;;;;; +1E6E4;TAI YO LETTER U;Lo;0;L;;;;;N;;;;; +1E6E5;TAI YO LETTER AE;Lo;0;L;;;;;N;;;;; +1E6E6;TAI YO SIGN AU;Mn;230;NSM;;;;;N;;;;; +1E6E7;TAI YO LETTER O;Lo;0;L;;;;;N;;;;; +1E6E8;TAI YO LETTER E;Lo;0;L;;;;;N;;;;; +1E6E9;TAI YO LETTER IA;Lo;0;L;;;;;N;;;;; +1E6EA;TAI YO LETTER UEA;Lo;0;L;;;;;N;;;;; +1E6EB;TAI YO LETTER UA;Lo;0;L;;;;;N;;;;; +1E6EC;TAI YO LETTER OO;Lo;0;L;;;;;N;;;;; +1E6ED;TAI YO LETTER AUE;Lo;0;L;;;;;N;;;;; +1E6EE;TAI YO SIGN AY;Mn;230;NSM;;;;;N;;;;; +1E6EF;TAI YO SIGN ANG;Mn;230;NSM;;;;;N;;;;; +1E6F0;TAI YO LETTER AN;Lo;0;L;;;;;N;;;;; +1E6F1;TAI YO LETTER AM;Lo;0;L;;;;;N;;;;; +1E6F2;TAI YO LETTER AK;Lo;0;L;;;;;N;;;;; +1E6F3;TAI YO LETTER AT;Lo;0;L;;;;;N;;;;; +1E6F4;TAI YO LETTER AP;Lo;0;L;;;;;N;;;;; +1E6F5;TAI YO SIGN OM;Mn;230;NSM;;;;;N;;;;; +1E6FE;TAI YO SYMBOL MUEANG;Lo;0;L;;;;;N;;;;; +1E6FF;TAI YO XAM LAI;Lm;0;L;;;;;N;;;;; 1E7E0;ETHIOPIC SYLLABLE HHYA;Lo;0;L;;;;;N;;;;; 1E7E1;ETHIOPIC SYLLABLE HHYU;Lo;0;L;;;;;N;;;;; 1E7E2;ETHIOPIC SYLLABLE HHYI;Lo;0;L;;;;;N;;;;; @@ -38079,6 +38511,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F6D5;HINDU TEMPLE;So;0;ON;;;;;N;;;;; 1F6D6;HUT;So;0;ON;;;;;N;;;;; 1F6D7;ELEVATOR;So;0;ON;;;;;N;;;;; +1F6D8;LANDSLIDE;So;0;ON;;;;;N;;;;; 1F6DC;WIRELESS;So;0;ON;;;;;N;;;;; 1F6DD;PLAYGROUND SLIDE;So;0;ON;;;;;N;;;;; 1F6DE;WHEEL;So;0;ON;;;;;N;;;;; @@ -38228,6 +38661,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F774;LOT OF FORTUNE;So;0;ON;;;;;N;;;;; 1F775;OCCULTATION;So;0;ON;;;;;N;;;;; 1F776;LUNAR ECLIPSE;So;0;ON;;;;;N;;;;; +1F777;VESTA FORM TWO;So;0;ON;;;;;N;;;;; +1F778;ASTRAEA FORM TWO;So;0;ON;;;;;N;;;;; +1F779;HYGIEA FORM TWO;So;0;ON;;;;;N;;;;; +1F77A;PARTHENOPE FORM TWO;So;0;ON;;;;;N;;;;; 1F77B;HAUMEA;So;0;ON;;;;;N;;;;; 1F77C;MAKEMAKE;So;0;ON;;;;;N;;;;; 1F77D;GONGGONG;So;0;ON;;;;;N;;;;; @@ -38498,6 +38935,15 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F8BB;SOUTH WEST ARROW FROM BAR;So;0;ON;;;;;N;;;;; 1F8C0;LEFTWARDS ARROW FROM DOWNWARDS ARROW;So;0;ON;;;;;N;;;;; 1F8C1;RIGHTWARDS ARROW FROM DOWNWARDS ARROW;So;0;ON;;;;;N;;;;; +1F8D0;LONG RIGHTWARDS ARROW OVER LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +1F8D1;LONG RIGHTWARDS HARPOON OVER LONG LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;; +1F8D2;LONG RIGHTWARDS HARPOON ABOVE SHORT LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;; +1F8D3;SHORT RIGHTWARDS HARPOON ABOVE LONG LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;; +1F8D4;LONG LEFTWARDS HARPOON ABOVE SHORT RIGHTWARDS HARPOON;Sm;0;ON;;;;;N;;;;; +1F8D5;SHORT LEFTWARDS HARPOON ABOVE LONG RIGHTWARDS HARPOON;Sm;0;ON;;;;;N;;;;; +1F8D6;LONG RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;; +1F8D7;LONG RIGHTWARDS ARROW WITH DOUBLE SLASH;Sm;0;ON;;;;;N;;;;; +1F8D8;LONG LEFT RIGHT ARROW WITH DEPENDENT LOBE;Sm;0;ON;;;;;N;;;;; 1F900;CIRCLED CROSS FORMEE WITH FOUR DOTS;So;0;ON;;;;;N;;;;; 1F901;CIRCLED CROSS FORMEE WITH TWO DOTS;So;0;ON;;;;;N;;;;; 1F902;CIRCLED CROSS FORMEE;So;0;ON;;;;;N;;;;; @@ -38838,6 +39284,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1FA51;BLACK CHESS KNIGHT-QUEEN;So;0;ON;;;;;N;;;;; 1FA52;BLACK CHESS KNIGHT-ROOK;So;0;ON;;;;;N;;;;; 1FA53;BLACK CHESS KNIGHT-BISHOP;So;0;ON;;;;;N;;;;; +1FA54;WHITE CHESS FERZ;So;0;ON;;;;;N;;;;; +1FA55;WHITE CHESS ALFIL;So;0;ON;;;;;N;;;;; +1FA56;BLACK CHESS FERZ;So;0;ON;;;;;N;;;;; +1FA57;BLACK CHESS ALFIL;So;0;ON;;;;;N;;;;; 1FA60;XIANGQI RED GENERAL;So;0;ON;;;;;N;;;;; 1FA61;XIANGQI RED MANDARIN;So;0;ON;;;;;N;;;;; 1FA62;XIANGQI RED ELEPHANT;So;0;ON;;;;;N;;;;; @@ -38875,6 +39325,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1FA87;MARACAS;So;0;ON;;;;;N;;;;; 1FA88;FLUTE;So;0;ON;;;;;N;;;;; 1FA89;HARP;So;0;ON;;;;;N;;;;; +1FA8A;TROMBONE;So;0;ON;;;;;N;;;;; +1FA8E;TREASURE CHEST;So;0;ON;;;;;N;;;;; 1FA8F;SHOVEL;So;0;ON;;;;;N;;;;; 1FA90;RINGED PLANET;So;0;ON;;;;;N;;;;; 1FA91;CHAIR;So;0;ON;;;;;N;;;;; @@ -38931,6 +39383,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1FAC4;PREGNANT PERSON;So;0;ON;;;;;N;;;;; 1FAC5;PERSON WITH CROWN;So;0;ON;;;;;N;;;;; 1FAC6;FINGERPRINT;So;0;ON;;;;;N;;;;; +1FAC8;HAIRY CREATURE;So;0;ON;;;;;N;;;;; +1FACD;ORCA;So;0;ON;;;;;N;;;;; 1FACE;MOOSE;So;0;ON;;;;;N;;;;; 1FACF;DONKEY;So;0;ON;;;;;N;;;;; 1FAD0;BLUEBERRIES;So;0;ON;;;;;N;;;;; @@ -38957,6 +39411,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1FAE7;BUBBLES;So;0;ON;;;;;N;;;;; 1FAE8;SHAKING FACE;So;0;ON;;;;;N;;;;; 1FAE9;FACE WITH BAGS UNDER EYES;So;0;ON;;;;;N;;;;; +1FAEA;DISTORTED FACE;So;0;ON;;;;;N;;;;; +1FAEF;FIGHT CLOUD;So;0;ON;;;;;N;;;;; 1FAF0;HAND WITH INDEX FINGER AND THUMB CROSSED;So;0;ON;;;;;N;;;;; 1FAF1;RIGHTWARDS HAND;So;0;ON;;;;;N;;;;; 1FAF2;LEFTWARDS HAND;So;0;ON;;;;;N;;;;; @@ -39215,14 +39671,15 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1FBF7;SEGMENTED DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; 1FBF8;SEGMENTED DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; 1FBF9;SEGMENTED DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1FBFA;ALARM BELL SYMBOL;So;0;ON;;;;;N;;;;; 20000;;Lo;0;L;;;;;N;;;;; 2A6DF;;Lo;0;L;;;;;N;;;;; 2A700;;Lo;0;L;;;;;N;;;;; -2B739;;Lo;0;L;;;;;N;;;;; +2B73F;;Lo;0;L;;;;;N;;;;; 2B740;;Lo;0;L;;;;;N;;;;; 2B81D;;Lo;0;L;;;;;N;;;;; 2B820;;Lo;0;L;;;;;N;;;;; -2CEA1;;Lo;0;L;;;;;N;;;;; +2CEAD;;Lo;0;L;;;;;N;;;;; 2CEB0;;Lo;0;L;;;;;N;;;;; 2EBE0;;Lo;0;L;;;;;N;;;;; 2EBF0;;Lo;0;L;;;;;N;;;;; @@ -39773,6 +40230,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 3134A;;Lo;0;L;;;;;N;;;;; 31350;;Lo;0;L;;;;;N;;;;; 323AF;;Lo;0;L;;;;;N;;;;; +323B0;;Lo;0;L;;;;;N;;;;; +33479;;Lo;0;L;;;;;N;;;;; E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;; E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;; E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;; diff --git a/src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakProperty.txt b/src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakProperty.txt index a4b7b6fbc3c..19b13571f34 100644 --- a/src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakProperty.txt +++ b/src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakProperty.txt @@ -1,6 +1,6 @@ -# GraphemeBreakProperty-16.0.0.txt -# Date: 2024-05-31, 18:09:38 GMT -# Copyright (c) 2024 Unicode, Inc. +# GraphemeBreakProperty-17.0.0.txt +# Date: 2025-06-30, 06:20:23 GMT +# © 2025 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use and license, see https://www.unicode.org/terms_of_use.html # @@ -30,12 +30,11 @@ 113D1 ; Prepend # Lo TULU-TIGALARI REPHA 1193F ; Prepend # Lo DIVES AKURU PREFIXED NASAL SIGN 11941 ; Prepend # Lo DIVES AKURU INITIAL RA -11A3A ; Prepend # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA 11A84..11A89 ; Prepend # Lo [6] SOYOMBO SIGN JIHVAMULIYA..SOYOMBO CLUSTER-INITIAL LETTER SA 11D46 ; Prepend # Lo MASARAM GONDI REPHA 11F02 ; Prepend # Lo KAWI SIGN REPHA -# Total code points: 28 +# Total code points: 27 # ================================================ @@ -243,7 +242,8 @@ E01F0..E0FFF ; Control # Cn [3600] .. 1A7F ; Extend # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT 1AB0..1ABD ; Extend # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW 1ABE ; Extend # Me COMBINING PARENTHESES OVERLAY -1ABF..1ACE ; Extend # Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T +1ABF..1ADD ; Extend # Mn [31] COMBINING LATIN SMALL LETTER W BELOW..COMBINING DOT-AND-RING BELOW +1AE0..1AEB ; Extend # Mn [12] COMBINING LEFT TACK ABOVE..COMBINING DOUBLE RIGHTWARDS ARROW ABOVE 1B00..1B03 ; Extend # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG 1B34 ; Extend # Mn BALINESE SIGN REREKAN 1B35 ; Extend # Mc BALINESE VOWEL SIGN TEDUNG @@ -339,7 +339,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 10D24..10D27 ; Extend # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI 10D69..10D6D ; Extend # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK 10EAB..10EAC ; Extend # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK -10EFC..10EFF ; Extend # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA +10EFA..10EFF ; Extend # Mn [6] ARABIC DOUBLE VERTICAL BAR BELOW..ARABIC SMALL LOW WORD MADDA 10F46..10F50 ; Extend # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW 10F82..10F85 ; Extend # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW 11001 ; Extend # Mn BRAHMI SIGN ANUSVARA @@ -430,6 +430,9 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11A59..11A5B ; Extend # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK 11A8A..11A96 ; Extend # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA 11A98..11A99 ; Extend # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11B60 ; Extend # Mn SHARADA VOWEL SIGN OE +11B62..11B64 ; Extend # Mn [3] SHARADA VOWEL SIGN UE..SHARADA VOWEL SIGN SHORT E +11B66 ; Extend # Mn SHARADA VOWEL SIGN CANDRA E 11C30..11C36 ; Extend # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L 11C38..11C3D ; Extend # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA 11C3F ; Extend # Mn BHAIKSUKI SIGN VIRAMA @@ -489,13 +492,17 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 1E2EC..1E2EF ; Extend # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI 1E4EC..1E4EF ; Extend # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH 1E5EE..1E5EF ; Extend # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR +1E6E3 ; Extend # Mn TAI YO SIGN UE +1E6E6 ; Extend # Mn TAI YO SIGN AU +1E6EE..1E6EF ; Extend # Mn [2] TAI YO SIGN AY..TAI YO SIGN ANG +1E6F5 ; Extend # Mn TAI YO SIGN OM 1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS 1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA 1F3FB..1F3FF ; Extend # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 2198 +# Total code points: 2237 # ================================================ @@ -646,6 +653,9 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 11A39 ; SpacingMark # Mc ZANABAZAR SQUARE SIGN VISARGA 11A57..11A58 ; SpacingMark # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU 11A97 ; SpacingMark # Mc SOYOMBO SIGN VISARGA +11B61 ; SpacingMark # Mc SHARADA VOWEL SIGN OOE +11B65 ; SpacingMark # Mc SHARADA VOWEL SIGN SHORT O +11B67 ; SpacingMark # Mc SHARADA VOWEL SIGN CANDRA O 11C2F ; SpacingMark # Mc BHAIKSUKI VOWEL SIGN AA 11C3E ; SpacingMark # Mc BHAIKSUKI SIGN VISARGA 11CA9 ; SpacingMark # Mc MARCHEN SUBJOINED LETTER YA @@ -661,7 +671,7 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 1612A..1612C ; SpacingMark # Mc [3] GURUNG KHEMA CONSONANT SIGN MEDIAL YA..GURUNG KHEMA CONSONANT SIGN MEDIAL HA 16F51..16F87 ; SpacingMark # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI -# Total code points: 378 +# Total code points: 381 # ================================================ diff --git a/src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakTest.txt b/src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakTest.txt index 3eb4b307e8e..e1215547c58 100644 --- a/src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakTest.txt +++ b/src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakTest.txt @@ -1,6 +1,6 @@ -# GraphemeBreakTest-16.0.0.txt -# Date: 2024-05-02, 15:02:48 GMT -# Copyright (c) 2024 Unicode, Inc. +# GraphemeBreakTest-17.0.0.txt +# Date: 2025-03-24, 14:45:55 GMT +# © 2025 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use and license, see https://www.unicode.org/terms_of_use.html # @@ -16,1106 +16,781 @@ # × wherever there is not. # the format can change, but currently it shows: # - the sample character name -# - (x) the Grapheme_Cluster_Break property value for the sample character +# - (x) the Grapheme_Cluster_Break property value for the sample character and +# any other properties relevant to the algorithm, as described in +# GraphemeBreakTest.html # - [x] the rule that determines whether there is a break or not, # as listed in the Rules section of GraphemeBreakTest.html # # These samples may be extended or changed in the future. # -÷ 0020 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0020 × 0308 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0020 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (CR) ÷ [0.3] -÷ 0020 × 0308 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0020 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (LF) ÷ [0.3] -÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0020 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (Control) ÷ [0.3] -÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0020 × 200C ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0020 × 0308 × 200C ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0020 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0020 × 0308 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0020 × 0A03 ÷ # ÷ [0.2] SPACE (Other) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0020 × 0308 × 0A03 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0020 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0020 × 0308 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0020 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0020 × 0308 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0020 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0020 × 0308 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0020 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0020 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0020 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0020 ÷ 0904 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0020 × 0308 ÷ 0904 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0020 ÷ 0D4E ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0020 × 0308 ÷ 0D4E ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0020 ÷ 0915 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0020 × 0308 ÷ 0915 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0020 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0020 × 0308 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0020 × 0900 ÷ # ÷ [0.2] SPACE (Other) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0020 × 0308 × 0900 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0020 × 094D ÷ # ÷ [0.2] SPACE (Other) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0020 × 0308 × 094D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0020 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] (Other) ÷ [0.3] -÷ 0020 × 0308 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 000D ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [4.0] SPACE (Other) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 000D ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] (CR) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] ÷ 000D × 000A ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 000D ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Control) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 000D ÷ 200C ÷ # ÷ [0.2] (CR) ÷ [4.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 000D ÷ 0308 × 200C ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 000D ÷ 0000 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Control) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0000 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 000D ÷ 094D ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 000D ÷ 0308 × 094D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 000D ÷ 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 000D ÷ 200C ÷ # ÷ [0.2] (CR) ÷ [4.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 000D ÷ 0308 × 200C ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 000D ÷ 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] ÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 000D ÷ 0600 ÷ # ÷ [0.2] (CR) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 000D ÷ 0A03 ÷ # ÷ [0.2] (CR) ÷ [4.0] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 000D ÷ 0308 × 0A03 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 06DD ÷ # ÷ [0.2] (CR) ÷ [4.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 06DD ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 000D ÷ 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 000D ÷ 1100 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] ÷ 000D ÷ 1160 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] ÷ 000D ÷ 11A8 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] ÷ 000D ÷ AC00 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 000D ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 000D ÷ 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 000D ÷ 0904 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 0904 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 000D ÷ 0D4E ÷ # ÷ [0.2] (CR) ÷ [4.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 0D4E ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 000D ÷ 0915 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 0915 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 000D ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 000D ÷ 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 0900 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 0308 × 0900 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 094D ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 0308 × 094D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 000D ÷ 0378 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Other) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 000A ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [4.0] SPACE (Other) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 000D ÷ 0915 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0915 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 000D ÷ 00A9 ÷ # ÷ [0.2] (CR) ÷ [4.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 00A9 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 000D ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [4.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 000D ÷ 0378 ÷ # ÷ [0.2] (CR) ÷ [4.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] ÷ 000A ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] (CR) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] ÷ 000A ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] (LF) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 000A ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Control) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 000A ÷ 200C ÷ # ÷ [0.2] (LF) ÷ [4.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 000A ÷ 0308 × 200C ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 000A ÷ 0000 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Control) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0000 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 000A ÷ 094D ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 000A ÷ 0308 × 094D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 000A ÷ 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 000A ÷ 200C ÷ # ÷ [0.2] (LF) ÷ [4.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 000A ÷ 0308 × 200C ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 000A ÷ 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] ÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 000A ÷ 0600 ÷ # ÷ [0.2] (LF) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 000A ÷ 0A03 ÷ # ÷ [0.2] (LF) ÷ [4.0] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 000A ÷ 0308 × 0A03 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 06DD ÷ # ÷ [0.2] (LF) ÷ [4.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 06DD ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 000A ÷ 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 000A ÷ 1100 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] ÷ 000A ÷ 1160 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] ÷ 000A ÷ 11A8 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] ÷ 000A ÷ AC00 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 000A ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 000A ÷ 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 000A ÷ 0904 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 0904 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 000A ÷ 0D4E ÷ # ÷ [0.2] (LF) ÷ [4.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 0D4E ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 000A ÷ 0915 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 0915 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 000A ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 000A ÷ 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 0900 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 0308 × 0900 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 094D ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 0308 × 094D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 000A ÷ 0378 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Other) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0001 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] SPACE (Other) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0001 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] (CR) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0001 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] (LF) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0001 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Control) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0001 ÷ 200C ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0001 ÷ 0308 × 200C ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0001 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0001 ÷ 0A03 ÷ # ÷ [0.2] (Control) ÷ [4.0] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0001 ÷ 0308 × 0A03 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0001 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0001 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0001 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0001 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0001 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0001 ÷ 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0001 ÷ 0308 × 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0001 ÷ 0904 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 0904 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0001 ÷ 0D4E ÷ # ÷ [0.2] (Control) ÷ [4.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 0D4E ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0001 ÷ 0915 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 0915 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0001 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0001 ÷ 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 0308 × 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 0900 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 0308 × 0900 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 094D ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 0308 × 094D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 0308 × 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0001 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Other) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 200C ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 200C × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 200C ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [5.0] (CR) ÷ [0.3] -÷ 200C × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 200C ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [5.0] (LF) ÷ [0.3] -÷ 200C × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 200C ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [5.0] (Control) ÷ [0.3] -÷ 200C × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 200C × 200C ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 200C × 0308 × 200C ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 200C ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 200C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 200C ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 200C × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 200C × 0A03 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 200C × 0308 × 0A03 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 200C ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 200C × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 200C ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 200C × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 200C ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 200C × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 200C ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 200C × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 200C ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 200C × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 200C × 0903 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 200C × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 200C ÷ 0904 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 200C × 0308 ÷ 0904 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 200C ÷ 0D4E ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 200C × 0308 ÷ 0D4E ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 200C ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 200C × 0308 ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 200C ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 200C × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 200C × 0300 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 200C × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 200C × 0900 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 200C × 0308 × 0900 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 200C × 094D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 200C × 0308 × 094D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 200C × 200D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 200C × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 200C ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) ÷ [999.0] (Other) ÷ [0.3] -÷ 200C × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 000A ÷ 0915 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0915 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 000A ÷ 00A9 ÷ # ÷ [0.2] (LF) ÷ [4.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 00A9 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 000A ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [4.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 000A ÷ 0378 ÷ # ÷ [0.2] (LF) ÷ [4.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0000 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] (CR) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 0000 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] (LF) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 0000 ÷ 0000 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Control) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 0000 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 0000 ÷ 094D ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0000 ÷ 0308 × 094D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0000 ÷ 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0000 ÷ 0308 × 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0000 ÷ 200C ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0000 ÷ 0308 × 200C ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0000 ÷ 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0000 ÷ 0308 × 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0000 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0000 ÷ 06DD ÷ # ÷ [0.2] (Control) ÷ [4.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 06DD ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0000 ÷ 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0000 ÷ 0308 × 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0000 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0000 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0000 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0000 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0000 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0000 ÷ 0915 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 0915 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0000 ÷ 00A9 ÷ # ÷ [0.2] (Control) ÷ [4.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 00A9 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0000 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0000 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0000 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 094D ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 094D × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 094D ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 094D × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 094D ÷ 0000 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 094D × 0308 ÷ 0000 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 094D × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 094D × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 094D × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 094D × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 094D × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 094D × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 094D × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 094D × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 094D ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 094D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 094D ÷ 06DD ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 094D × 0308 ÷ 06DD ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 094D × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 094D × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 094D ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 094D × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 094D ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 094D × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 094D ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 094D × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 094D ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 094D × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 094D ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 094D × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 094D ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 094D × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 094D ÷ 00A9 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 094D × 0308 ÷ 00A9 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 094D ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 094D × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 094D ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 094D × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0300 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 0300 × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 0300 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 0300 ÷ 0000 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 0300 × 0308 ÷ 0000 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 0300 × 094D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0300 × 0308 × 094D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0300 × 200C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0300 × 0308 × 200C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 ÷ 06DD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0300 × 0308 ÷ 06DD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0300 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0300 × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0300 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0300 × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0300 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0300 × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0300 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0300 ÷ 0915 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0300 × 0308 ÷ 0915 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0300 ÷ 00A9 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0300 × 0308 ÷ 00A9 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0300 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0300 × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 200C ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [5.0] (CR) ÷ [0.3] +÷ 200C × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 200C ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [5.0] (LF) ÷ [0.3] +÷ 200C × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 200C ÷ 0000 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [5.0] (Control) ÷ [0.3] +÷ 200C × 0308 ÷ 0000 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 200C × 094D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 200C × 0308 × 094D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 200C × 0300 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 200C × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 200C × 200C ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 200C × 0308 × 200C ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 200C × 200D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 200C × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 200C ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200C ÷ 06DD ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 200C × 0308 ÷ 06DD ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 200C × 0903 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200C × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200C ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200C × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200C ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200C × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200C ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200C × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200C ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200C × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200C ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200C × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200C ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 200C × 0308 ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 200C ÷ 00A9 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 200C × 0308 ÷ 00A9 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 200C ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 200C × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 200C ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 200C × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] (CR) ÷ [0.3] +÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] (LF) ÷ [0.3] +÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 200D ÷ 0000 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] (Control) ÷ [0.3] +÷ 200D × 0308 ÷ 0000 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 200D × 094D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 200D × 0308 × 094D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 200D × 200C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 200D × 0308 × 200C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D ÷ 06DD ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 200D × 0308 ÷ 06DD ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200D ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200D × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200D ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200D × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200D ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200D × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200D ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200D ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 200D × 0308 ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 200D ÷ 00A9 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 200D × 0308 ÷ 00A9 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 200D ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 200D × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] ÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (CR) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] ÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (LF) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (Control) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 1F1E6 × 200C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 1F1E6 × 0308 × 200C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 1F1E6 ÷ 0000 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (Control) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0000 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 1F1E6 × 094D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 1F1E6 × 0308 × 094D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 1F1E6 × 200C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 1F1E6 × 0308 × 200C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] ÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 1F1E6 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 1F1E6 × 0A03 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 1F1E6 × 0308 × 0A03 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 ÷ 06DD ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 06DD ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 1F1E6 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] ÷ 1F1E6 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] ÷ 1F1E6 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] ÷ 1F1E6 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 1F1E6 ÷ 0904 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0904 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 1F1E6 ÷ 0D4E ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0D4E ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1F1E6 ÷ 0915 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0915 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 1F1E6 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 × 0900 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 × 0308 × 0900 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 × 094D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 × 0308 × 094D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 1F1E6 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] (Other) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0600 × 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] SPACE (Other) ÷ [0.3] -÷ 0600 × 0308 ÷ 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0600 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (CR) ÷ [0.3] -÷ 0600 × 0308 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0600 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (LF) ÷ [0.3] -÷ 0600 × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0600 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (Control) ÷ [0.3] -÷ 0600 × 0308 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0600 × 200C ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0600 × 0308 × 200C ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0600 × 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0600 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0600 × 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0600 × 0308 ÷ 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0600 × 0A03 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0600 × 0308 × 0A03 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0600 × 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0600 × 0308 ÷ 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0600 × 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0600 × 0308 ÷ 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0600 × 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0600 × 0308 ÷ 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0600 × AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0600 × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0600 × AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0600 × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0600 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0600 × 0308 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0600 × 0904 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0600 × 0308 ÷ 0904 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0600 × 0D4E ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0600 × 0308 ÷ 0D4E ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0600 × 0915 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0600 × 0308 ÷ 0915 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0600 × 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] WATCH (ExtPict) ÷ [0.3] -÷ 0600 × 0308 ÷ 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0600 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0600 × 0308 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0600 × 0900 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0600 × 0308 × 0900 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0600 × 094D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0600 × 0308 × 094D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0600 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0600 × 0308 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0600 × 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] (Other) ÷ [0.3] -÷ 0600 × 0308 ÷ 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0A03 ÷ 0020 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0A03 × 0308 ÷ 0020 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0A03 ÷ 000D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [5.0] (CR) ÷ [0.3] -÷ 0A03 × 0308 ÷ 000D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0A03 ÷ 000A ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [5.0] (LF) ÷ [0.3] -÷ 0A03 × 0308 ÷ 000A ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0A03 ÷ 0001 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [5.0] (Control) ÷ [0.3] -÷ 0A03 × 0308 ÷ 0001 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0A03 × 200C ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0A03 × 0308 × 200C ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0A03 ÷ 1F1E6 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0A03 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0A03 ÷ 0600 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0A03 × 0308 ÷ 0600 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0A03 × 0A03 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0A03 × 0308 × 0A03 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0A03 ÷ 1100 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0A03 × 0308 ÷ 1100 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0A03 ÷ 1160 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0A03 × 0308 ÷ 1160 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0A03 ÷ 11A8 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0A03 × 0308 ÷ 11A8 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0A03 ÷ AC00 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0A03 × 0308 ÷ AC00 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0A03 ÷ AC01 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0A03 × 0308 ÷ AC01 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0A03 × 0903 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0A03 × 0308 × 0903 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0A03 ÷ 0904 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0A03 × 0308 ÷ 0904 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0A03 ÷ 0D4E ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0A03 × 0308 ÷ 0D4E ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0A03 ÷ 0915 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0A03 × 0308 ÷ 0915 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0A03 ÷ 231A ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0A03 × 0308 ÷ 231A ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0A03 × 0300 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0A03 × 0308 × 0300 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0A03 × 0900 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0A03 × 0308 × 0900 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0A03 × 094D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0A03 × 0308 × 094D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0A03 × 200D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0A03 × 0308 × 200D ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0A03 ÷ 0378 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [999.0] (Other) ÷ [0.3] -÷ 0A03 × 0308 ÷ 0378 ÷ # ÷ [0.2] GURMUKHI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 1100 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 1100 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1F1E6 ÷ 0915 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0915 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 1F1E6 ÷ 00A9 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 00A9 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 1F1E6 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 06DD ÷ 000D ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) ÷ [5.0] (CR) ÷ [0.3] +÷ 06DD × 0308 ÷ 000D ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 06DD ÷ 000A ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) ÷ [5.0] (LF) ÷ [0.3] +÷ 06DD × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 06DD ÷ 0000 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) ÷ [5.0] (Control) ÷ [0.3] +÷ 06DD × 0308 ÷ 0000 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 06DD × 094D ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 06DD × 0308 × 094D ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 06DD × 0300 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 06DD × 0308 × 0300 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 06DD × 200C ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 06DD × 0308 × 200C ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 06DD × 200D ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 06DD × 0308 × 200D ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 06DD × 1F1E6 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 06DD × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 06DD × 06DD ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.2] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 06DD × 0308 ÷ 06DD ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 06DD × 0903 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 06DD × 0308 × 0903 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 06DD × 1100 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.2] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 06DD × 0308 ÷ 1100 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 06DD × 1160 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.2] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 06DD × 0308 ÷ 1160 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 06DD × 11A8 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.2] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 06DD × 0308 ÷ 11A8 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 06DD × AC00 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.2] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 06DD × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 06DD × AC01 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 06DD × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 06DD × 0915 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 06DD × 0308 ÷ 0915 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 06DD × 00A9 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.2] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 06DD × 0308 ÷ 00A9 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 06DD × 0020 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 06DD × 0308 ÷ 0020 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 06DD × 0378 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.2] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 06DD × 0308 ÷ 0378 ÷ # ÷ [0.2] ARABIC END OF AYAH (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0903 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (CR) ÷ [0.3] +÷ 0903 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 0903 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (LF) ÷ [0.3] +÷ 0903 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 0903 ÷ 0000 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (Control) ÷ [0.3] +÷ 0903 × 0308 ÷ 0000 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 0903 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0903 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0903 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0903 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0903 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0903 ÷ 06DD ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0903 × 0308 ÷ 06DD ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0903 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0903 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0903 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0903 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0903 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0903 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0903 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0903 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0903 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0903 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0903 × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0903 ÷ 00A9 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0903 × 0308 ÷ 00A9 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0903 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0903 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0903 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] ÷ 1100 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (CR) ÷ [0.3] -÷ 1100 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 1100 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] ÷ 1100 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (LF) ÷ [0.3] -÷ 1100 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 1100 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (Control) ÷ [0.3] -÷ 1100 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 1100 × 200C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 1100 × 0308 × 200C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 1100 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 1100 ÷ 0000 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (Control) ÷ [0.3] +÷ 1100 × 0308 ÷ 0000 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 1100 × 094D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 1100 × 0308 × 094D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 1100 × 200C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 1100 × 0308 × 200C ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1100 × 0308 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] ÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 1100 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 1100 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 1100 × 0A03 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 1100 × 0308 × 0A03 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1100 ÷ 06DD ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 1100 × 0308 ÷ 06DD ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 1100 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 1100 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1100 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] ÷ 1100 × 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 1100 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1100 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] ÷ 1100 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 1100 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1100 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] ÷ 1100 × AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 1100 × AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1100 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 1100 ÷ 0904 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 1100 × 0308 ÷ 0904 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 1100 ÷ 0D4E ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1100 × 0308 ÷ 0D4E ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1100 ÷ 0915 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 1100 × 0308 ÷ 0915 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 1100 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 1100 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1100 × 0900 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1100 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1100 × 094D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 1100 × 0308 × 094D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 1100 × 0308 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 1100 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] (Other) ÷ [0.3] -÷ 1100 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 1160 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 1160 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1100 ÷ 0915 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 1100 × 0308 ÷ 0915 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 1100 ÷ 00A9 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 1100 × 0308 ÷ 00A9 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 1100 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 1100 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 1100 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 1100 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] ÷ 1160 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (CR) ÷ [0.3] -÷ 1160 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 1160 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] ÷ 1160 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (LF) ÷ [0.3] -÷ 1160 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 1160 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (Control) ÷ [0.3] -÷ 1160 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 1160 × 200C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 1160 × 0308 × 200C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 1160 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 1160 ÷ 0000 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (Control) ÷ [0.3] +÷ 1160 × 0308 ÷ 0000 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 1160 × 094D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 1160 × 0308 × 094D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 1160 × 200C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 1160 × 0308 × 200C ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1160 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] ÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 1160 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 1160 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 1160 × 0A03 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 1160 × 0308 × 0A03 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1160 ÷ 06DD ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 1160 × 0308 ÷ 06DD ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 1160 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 1160 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 1160 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1160 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] ÷ 1160 × 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 1160 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1160 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] ÷ 1160 × 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 1160 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1160 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] ÷ 1160 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 1160 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1160 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 1160 ÷ 0904 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 1160 × 0308 ÷ 0904 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 1160 ÷ 0D4E ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1160 × 0308 ÷ 0D4E ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 1160 ÷ 0915 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 1160 × 0308 ÷ 0915 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 1160 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 1160 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 1160 × 0900 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1160 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 1160 × 094D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 1160 × 0308 × 094D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 1160 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 1160 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] (Other) ÷ [0.3] -÷ 1160 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 11A8 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 11A8 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1160 ÷ 0915 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 1160 × 0308 ÷ 0915 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 1160 ÷ 00A9 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 1160 × 0308 ÷ 00A9 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 1160 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 1160 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 1160 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 1160 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] ÷ 11A8 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (CR) ÷ [0.3] -÷ 11A8 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 11A8 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] ÷ 11A8 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (LF) ÷ [0.3] -÷ 11A8 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 11A8 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (Control) ÷ [0.3] -÷ 11A8 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 11A8 × 200C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 11A8 × 0308 × 200C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ 11A8 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 11A8 ÷ 0000 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (Control) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0000 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 11A8 × 094D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 11A8 × 0308 × 094D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 11A8 × 200C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 11A8 × 0308 × 200C ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 11A8 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] ÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 11A8 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 11A8 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 11A8 × 0A03 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 11A8 × 0308 × 0A03 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 11A8 ÷ 06DD ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 11A8 × 0308 ÷ 06DD ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 11A8 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 11A8 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] ÷ 11A8 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 11A8 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] ÷ 11A8 × 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 11A8 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 11A8 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] ÷ 11A8 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 11A8 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 11A8 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 11A8 ÷ 0904 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 11A8 × 0308 ÷ 0904 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 11A8 ÷ 0D4E ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 11A8 × 0308 ÷ 0D4E ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 11A8 ÷ 0915 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 11A8 × 0308 ÷ 0915 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 11A8 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 11A8 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 11A8 × 0900 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 11A8 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 11A8 × 094D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 11A8 × 0308 × 094D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 11A8 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 11A8 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] (Other) ÷ [0.3] -÷ 11A8 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ AC00 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ AC00 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 11A8 ÷ 0915 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0915 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 11A8 ÷ 00A9 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 11A8 × 0308 ÷ 00A9 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 11A8 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 11A8 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] ÷ AC00 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (CR) ÷ [0.3] -÷ AC00 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ AC00 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] ÷ AC00 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (LF) ÷ [0.3] -÷ AC00 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ AC00 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (Control) ÷ [0.3] -÷ AC00 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ AC00 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ AC00 × 0308 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ AC00 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ AC00 ÷ 0000 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (Control) ÷ [0.3] +÷ AC00 × 0308 ÷ 0000 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ AC00 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ AC00 × 0308 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ AC00 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ AC00 × 0308 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ AC00 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] ÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ AC00 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ AC00 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ AC00 × 0A03 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ AC00 × 0308 × 0A03 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC00 ÷ 06DD ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ AC00 × 0308 ÷ 06DD ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ AC00 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ AC00 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ AC00 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC00 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] ÷ AC00 × 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ AC00 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ AC00 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] ÷ AC00 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ AC00 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ AC00 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] ÷ AC00 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ AC00 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ AC00 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ AC00 ÷ 0904 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ AC00 × 0308 ÷ 0904 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ AC00 ÷ 0D4E ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ AC00 × 0308 ÷ 0D4E ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ AC00 ÷ 0915 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ AC00 × 0308 ÷ 0915 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ AC00 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ AC00 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ AC00 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ AC00 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ AC00 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ AC00 × 0308 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ AC00 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ AC00 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] (Other) ÷ [0.3] -÷ AC00 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ AC01 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ AC01 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ AC00 ÷ 0915 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ AC00 × 0308 ÷ 0915 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ AC00 ÷ 00A9 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ AC00 × 0308 ÷ 00A9 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ AC00 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ AC00 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ AC00 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ AC00 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] ÷ AC01 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (CR) ÷ [0.3] -÷ AC01 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ AC01 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] ÷ AC01 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (LF) ÷ [0.3] -÷ AC01 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ AC01 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (Control) ÷ [0.3] -÷ AC01 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ AC01 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ AC01 × 0308 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] +÷ AC01 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ AC01 ÷ 0000 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (Control) ÷ [0.3] +÷ AC01 × 0308 ÷ 0000 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ AC01 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ AC01 × 0308 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ AC01 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ AC01 × 0308 × 200C ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] ÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ AC01 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ AC01 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ AC01 × 0A03 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ AC01 × 0308 × 0A03 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC01 ÷ 06DD ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ AC01 × 0308 ÷ 06DD ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ AC01 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ AC01 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ AC01 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC01 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] ÷ AC01 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ AC01 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ AC01 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] ÷ AC01 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ AC01 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ AC01 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] ÷ AC01 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ AC01 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ AC01 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ AC01 ÷ 0904 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ AC01 × 0308 ÷ 0904 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ AC01 ÷ 0D4E ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ AC01 × 0308 ÷ 0D4E ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ AC01 ÷ 0915 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ AC01 × 0308 ÷ 0915 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ AC01 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ AC01 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ AC01 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ AC01 × 0308 × 0900 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ AC01 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ AC01 × 0308 × 094D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ AC01 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] (Other) ÷ [0.3] -÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0903 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0903 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [5.0] (CR) ÷ [0.3] -÷ 0903 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0903 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [5.0] (LF) ÷ [0.3] -÷ 0903 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0903 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [5.0] (Control) ÷ [0.3] -÷ 0903 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0903 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0903 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0903 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0903 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0903 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0903 × 0308 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0903 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0903 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0903 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0903 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0903 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0903 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0903 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0903 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0903 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0903 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0903 × 0308 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0903 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0903 × 0308 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0903 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0903 × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0903 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0903 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0903 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0903 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0903 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0903 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0903 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0903 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] (Other) ÷ [0.3] -÷ 0903 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0904 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0904 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0904 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [5.0] (CR) ÷ [0.3] -÷ 0904 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0904 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [5.0] (LF) ÷ [0.3] -÷ 0904 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0904 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [5.0] (Control) ÷ [0.3] -÷ 0904 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0904 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0904 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0904 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0904 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0904 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0904 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0904 × 0A03 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0904 × 0308 × 0A03 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0904 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0904 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0904 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0904 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0904 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0904 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0904 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0904 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0904 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0904 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0904 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0904 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0904 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0904 × 0308 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0904 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0904 × 0308 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0904 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0904 × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0904 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0904 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0904 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0904 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0904 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0904 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0904 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0904 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0904 × 200D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0904 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0904 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [999.0] (Other) ÷ [0.3] -÷ 0904 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0D4E × 0020 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] SPACE (Other) ÷ [0.3] -÷ 0D4E × 0308 ÷ 0020 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0D4E ÷ 000D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [5.0] (CR) ÷ [0.3] -÷ 0D4E × 0308 ÷ 000D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0D4E ÷ 000A ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [5.0] (LF) ÷ [0.3] -÷ 0D4E × 0308 ÷ 000A ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0D4E ÷ 0001 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [5.0] (Control) ÷ [0.3] -÷ 0D4E × 0308 ÷ 0001 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0D4E × 200C ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0D4E × 0308 × 200C ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0D4E × 1F1E6 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0D4E × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0D4E × 0600 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0D4E × 0308 ÷ 0600 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0D4E × 0A03 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0D4E × 0308 × 0A03 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0D4E × 1100 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0D4E × 0308 ÷ 1100 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0D4E × 1160 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0D4E × 0308 ÷ 1160 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0D4E × 11A8 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0D4E × 0308 ÷ 11A8 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0D4E × AC00 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0D4E × 0308 ÷ AC00 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0D4E × AC01 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0D4E × 0308 ÷ AC01 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0D4E × 0903 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0D4E × 0308 × 0903 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0D4E × 0904 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0D4E × 0308 ÷ 0904 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0D4E × 0D4E ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0D4E × 0308 ÷ 0D4E ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0D4E × 0915 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0D4E × 0308 ÷ 0915 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0D4E × 231A ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] WATCH (ExtPict) ÷ [0.3] -÷ 0D4E × 0308 ÷ 231A ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0D4E × 0300 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 0308 × 0300 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 0900 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 0308 × 0900 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 094D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 0308 × 094D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 200D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 0308 × 200D ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0D4E × 0378 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.2] (Other) ÷ [0.3] -÷ 0D4E × 0308 ÷ 0378 ÷ # ÷ [0.2] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0915 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0915 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0915 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [5.0] (CR) ÷ [0.3] -÷ 0915 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0915 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [5.0] (LF) ÷ [0.3] -÷ 0915 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0915 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [5.0] (Control) ÷ [0.3] -÷ 0915 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0915 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0915 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0915 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0915 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0915 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0915 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0915 × 0A03 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0915 × 0308 × 0A03 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0915 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0915 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0915 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0915 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0915 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0915 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0915 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0915 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0915 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0915 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0915 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0915 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0915 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0915 × 0308 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0915 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0915 × 0308 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0915 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0915 × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0915 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0915 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0915 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0915 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0915 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0915 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0915 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0915 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0915 × 200D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0915 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0915 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] (Other) ÷ [0.3] -÷ 0915 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 231A ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 231A × 0308 ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 231A ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (CR) ÷ [0.3] -÷ 231A × 0308 ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 231A ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (LF) ÷ [0.3] -÷ 231A × 0308 ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 231A ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (Control) ÷ [0.3] -÷ 231A × 0308 ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 231A × 200C ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 231A × 0308 × 200C ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 231A ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 231A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 231A ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 231A × 0308 ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 231A × 0A03 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 231A × 0308 × 0A03 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 231A ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 231A × 0308 ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 231A ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 231A × 0308 ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 231A ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 231A × 0308 ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 231A ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 231A × 0308 ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 231A ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 231A × 0308 ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 231A × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 231A × 0308 × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 231A ÷ 0904 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 231A × 0308 ÷ 0904 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 231A ÷ 0D4E ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 231A × 0308 ÷ 0D4E ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 231A ÷ 0915 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 231A × 0308 ÷ 0915 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 231A ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 231A × 0308 ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 231A × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 231A × 0308 × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 231A × 0900 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 231A × 0308 × 0900 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 231A × 094D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 231A × 0308 × 094D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 231A × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 231A × 0308 × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 231A ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] (Other) ÷ [0.3] -÷ 231A × 0308 ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0300 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0300 × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0300 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0300 × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0300 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0300 × 200C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0300 × 0308 × 200C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0300 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0300 × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0300 × 0A03 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0300 × 0308 × 0A03 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0300 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0300 × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0300 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0300 × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0300 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0300 × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0300 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0300 ÷ 0904 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0300 × 0308 ÷ 0904 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0300 ÷ 0D4E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0300 × 0308 ÷ 0D4E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0300 ÷ 0915 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0300 × 0308 ÷ 0915 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0300 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0300 × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0300 × 0900 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0300 × 0308 × 0900 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0300 × 094D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0300 × 0308 × 094D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0900 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0900 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0900 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0900 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0900 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0900 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0900 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0900 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0900 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0900 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0900 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0900 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0900 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0900 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0900 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0900 × 0308 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0900 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0900 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0900 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0900 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0900 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0900 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0900 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0900 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0900 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0900 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0900 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0308 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 × 0308 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0900 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0900 × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0900 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0900 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0900 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0900 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0900 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0900 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0900 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0900 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 094D ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 094D × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 094D ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 094D × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 094D ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 094D × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 094D ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 094D × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 094D × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 094D × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 094D ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 094D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 094D ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 094D × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 094D × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 094D × 0308 × 0A03 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 094D ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 094D × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 094D ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 094D × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 094D ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 094D × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 094D ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 094D × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 094D ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 094D × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 094D × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 094D × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 094D ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 094D × 0308 ÷ 0904 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 094D ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 094D × 0308 ÷ 0D4E ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 094D ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 094D × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 094D ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 094D × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 094D × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 094D × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 094D × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 094D × 0308 × 0900 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 094D × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 094D × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 094D × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 094D × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 094D ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 094D × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 200D × 200C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 200D × 0308 × 200C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 200D ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 200D × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 200D × 0A03 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 200D × 0308 × 0A03 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 200D ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 200D × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 200D ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 200D × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 200D ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 200D × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 200D ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 200D ÷ 0904 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 200D × 0308 ÷ 0904 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 200D ÷ 0D4E ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 200D × 0308 ÷ 0D4E ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 200D ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 200D × 0308 ÷ 0915 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 200D ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 200D × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 200D × 0900 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 200D × 0308 × 0900 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 200D × 094D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 200D × 0308 × 094D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 200D ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 200D × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 0378 ÷ 0020 ÷ # ÷ [0.2] (Other) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0378 × 0308 ÷ 0020 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 0378 ÷ 000D ÷ # ÷ [0.2] (Other) ÷ [5.0] (CR) ÷ [0.3] -÷ 0378 × 0308 ÷ 000D ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] -÷ 0378 ÷ 000A ÷ # ÷ [0.2] (Other) ÷ [5.0] (LF) ÷ [0.3] -÷ 0378 × 0308 ÷ 000A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] -÷ 0378 ÷ 0001 ÷ # ÷ [0.2] (Other) ÷ [5.0] (Control) ÷ [0.3] -÷ 0378 × 0308 ÷ 0001 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] -÷ 0378 × 200C ÷ # ÷ [0.2] (Other) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0378 × 0308 × 200C ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH NON-JOINER (Extend) ÷ [0.3] -÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -÷ 0378 ÷ 0600 ÷ # ÷ [0.2] (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0378 × 0308 ÷ 0600 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] -÷ 0378 × 0A03 ÷ # ÷ [0.2] (Other) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0378 × 0308 × 0A03 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] GURMUKHI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 0378 ÷ 1100 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0378 × 0308 ÷ 1100 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 0378 ÷ 1160 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0378 × 0308 ÷ 1160 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 0378 ÷ 11A8 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0378 × 0308 ÷ 11A8 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 0378 ÷ AC00 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 0378 ÷ AC01 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0378 × 0903 ÷ # ÷ [0.2] (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [0.3] -÷ 0378 ÷ 0904 ÷ # ÷ [0.2] (Other) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0378 × 0308 ÷ 0904 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER SHORT A (ConjunctLinkingScripts) ÷ [0.3] -÷ 0378 ÷ 0D4E ÷ # ÷ [0.2] (Other) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0378 × 0308 ÷ 0D4E ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] MALAYALAM LETTER DOT REPH (Prepend_ConjunctLinkingScripts) ÷ [0.3] -÷ 0378 ÷ 0915 ÷ # ÷ [0.2] (Other) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0378 × 0308 ÷ 0915 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0378 ÷ 231A ÷ # ÷ [0.2] (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0378 × 0308 ÷ 231A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] -÷ 0378 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] -÷ 0378 × 0900 ÷ # ÷ [0.2] (Other) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0378 × 0308 × 0900 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN INVERTED CANDRABINDU (Extend_ConjunctLinkingScripts_ExtCccZwj) ÷ [0.3] -÷ 0378 × 094D ÷ # ÷ [0.2] (Other) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0378 × 0308 × 094D ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [0.3] -÷ 0378 × 200D ÷ # ÷ [0.2] (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0378 × 0308 × 200D ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0378 ÷ 0378 ÷ # ÷ [0.2] (Other) ÷ [999.0] (Other) ÷ [0.3] -÷ 0378 × 0308 ÷ 0378 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] -÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [4.0] LATIN SMALL LETTER A (Other) ÷ [5.0] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3] -÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3] -÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC LETTER NOON (Other) ÷ [0.3] -÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ AC01 ÷ 0915 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ AC01 × 0308 ÷ 0915 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ AC01 ÷ 00A9 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ AC01 × 0308 ÷ 00A9 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ AC01 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ AC01 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ AC01 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0915 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [5.0] (CR) ÷ [0.3] +÷ 0915 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 0915 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [5.0] (LF) ÷ [0.3] +÷ 0915 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 0915 ÷ 0000 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [5.0] (Control) ÷ [0.3] +÷ 0915 × 0308 ÷ 0000 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 0915 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0915 × 0308 × 094D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0915 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0915 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0915 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0915 × 0308 × 200C ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0915 × 200D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0915 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0915 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0915 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0915 ÷ 06DD ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0915 × 0308 ÷ 06DD ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0915 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0915 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0915 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0915 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0915 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0915 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0915 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0915 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0915 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0915 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0915 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0915 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0915 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0915 × 0308 ÷ 0915 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0915 ÷ 00A9 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0915 × 0308 ÷ 00A9 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0915 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0915 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0915 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0915 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 00A9 ÷ 000D ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [5.0] (CR) ÷ [0.3] +÷ 00A9 × 0308 ÷ 000D ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 00A9 ÷ 000A ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [5.0] (LF) ÷ [0.3] +÷ 00A9 × 0308 ÷ 000A ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 00A9 ÷ 0000 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [5.0] (Control) ÷ [0.3] +÷ 00A9 × 0308 ÷ 0000 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 00A9 × 094D ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 00A9 × 0308 × 094D ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 00A9 × 0300 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 00A9 × 0308 × 0300 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 00A9 × 200C ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 00A9 × 0308 × 200C ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 00A9 × 200D ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 00A9 × 0308 × 200D ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 00A9 ÷ 1F1E6 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 00A9 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 00A9 ÷ 06DD ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 00A9 × 0308 ÷ 06DD ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 00A9 × 0903 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 00A9 × 0308 × 0903 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 00A9 ÷ 1100 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 00A9 × 0308 ÷ 1100 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 00A9 ÷ 1160 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 00A9 × 0308 ÷ 1160 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 00A9 ÷ 11A8 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 00A9 × 0308 ÷ 11A8 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 00A9 ÷ AC00 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 00A9 × 0308 ÷ AC00 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 00A9 ÷ AC01 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 00A9 × 0308 ÷ AC01 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 00A9 ÷ 0915 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 00A9 × 0308 ÷ 0915 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 00A9 ÷ 00A9 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 00A9 × 0308 ÷ 00A9 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 00A9 ÷ 0020 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 00A9 × 0308 ÷ 0020 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 00A9 ÷ 0378 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 00A9 × 0308 ÷ 0378 ÷ # ÷ [0.2] COPYRIGHT SIGN (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0020 ÷ 000D ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [5.0] (CR) ÷ [0.3] +÷ 0020 × 0308 ÷ 000D ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 0020 ÷ 000A ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [5.0] (LF) ÷ [0.3] +÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 0020 ÷ 0000 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [5.0] (Control) ÷ [0.3] +÷ 0020 × 0308 ÷ 0000 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 0020 × 094D ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0020 × 0308 × 094D ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0020 × 200C ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0020 × 0308 × 200C ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 ÷ 06DD ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0020 × 0308 ÷ 06DD ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0020 × 0903 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0020 ÷ 1100 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0020 × 0308 ÷ 1100 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0020 ÷ 1160 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0020 × 0308 ÷ 1160 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0020 ÷ 11A8 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0020 × 0308 ÷ 11A8 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0020 ÷ AC00 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0020 ÷ AC01 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0020 ÷ 0915 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0020 × 0308 ÷ 0915 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0020 ÷ 00A9 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0020 × 0308 ÷ 00A9 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0020 ÷ 0020 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0020 × 0308 ÷ 0020 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0020 ÷ 0378 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0020 × 0308 ÷ 0378 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0378 ÷ 000D ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [5.0] (CR) ÷ [0.3] +÷ 0378 × 0308 ÷ 000D ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (CR) ÷ [0.3] +÷ 0378 ÷ 000A ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [5.0] (LF) ÷ [0.3] +÷ 0378 × 0308 ÷ 000A ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (LF) ÷ [0.3] +÷ 0378 ÷ 0000 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [5.0] (Control) ÷ [0.3] +÷ 0378 × 0308 ÷ 0000 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [5.0] (Control) ÷ [0.3] +÷ 0378 × 094D ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0378 × 0308 × 094D ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [0.3] +÷ 0378 × 0300 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING GRAVE ACCENT (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0378 × 200C ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0378 × 0308 × 200C ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH NON-JOINER (ExtendmConjunctLinkermConjunctExtender) ÷ [0.3] +÷ 0378 × 200D ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0378 × 0308 × 200D ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0378 ÷ 06DD ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0378 × 0308 ÷ 06DD ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] ARABIC END OF AYAH (Prepend) ÷ [0.3] +÷ 0378 × 0903 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0378 ÷ 1100 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0378 × 0308 ÷ 1100 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0378 ÷ 1160 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0378 × 0308 ÷ 1160 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0378 ÷ 11A8 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0378 × 0308 ÷ 11A8 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0378 ÷ AC00 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0378 ÷ AC01 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0378 ÷ 0915 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0378 × 0308 ÷ 0915 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 0378 ÷ 00A9 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0378 × 0308 ÷ 00A9 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] COPYRIGHT SIGN (ExtPict) ÷ [0.3] +÷ 0378 ÷ 0020 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0378 × 0308 ÷ 0020 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0378 ÷ 0378 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0378 × 0308 ÷ 0378 ÷ # ÷ [0.2] (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [4.0] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) ÷ [5.0] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (XXmLinkingConsonantmExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] ARABIC LETTER NOON (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (XXmLinkingConsonantmExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] SPACE (XXmLinkingConsonantmExtPict) ÷ [0.3] ÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] ÷ AC00 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] ÷ AC01 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] -÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] -÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] -÷ 0061 ÷ 1F1E6 × 200D ÷ 1F1E7 × 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] -÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 × 1F1E9 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER D (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] -÷ 0061 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] -÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] -÷ 0061 × 0903 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark_ConjunctLinkingScripts) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] -÷ 0061 ÷ 0600 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) × [9.2] LATIN SMALL LETTER B (Other) ÷ [0.3] -÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [999.0] BABY (ExtPict) ÷ [0.3] -÷ 0061 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [999.0] BABY (ExtPict) ÷ [0.3] -÷ 0061 × 1F3FF ÷ 1F476 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [999.0] BABY (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] -÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ExtCccZwj) ÷ [0.3] -÷ 1F6D1 × 200D × 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] -÷ 0061 × 200D ÷ 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] -÷ 2701 × 200D × 2701 ÷ # ÷ [0.2] UPPER BLADE SCISSORS (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] UPPER BLADE SCISSORS (Other) ÷ [0.3] -÷ 0061 × 200D ÷ 2701 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] UPPER BLADE SCISSORS (Other) ÷ [0.3] -÷ 0915 ÷ 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) ÷ [999.0] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0915 × 094D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.3] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0915 × 094D × 094D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.3] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0915 × 094D × 200D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.3] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0915 × 093C × 200D × 094D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.3] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0915 × 093C × 094D × 200D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctLinkingScripts_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.3] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0915 × 094D × 0924 × 094D × 092F ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.3] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.3] DEVANAGARI LETTER YA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0915 × 094D ÷ 0061 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] LATIN SMALL LETTER A (Other) ÷ [0.3] -÷ 0061 × 094D ÷ 0924 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 003F × 094D ÷ 0924 ÷ # ÷ [0.2] QUESTION MARK (Other) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) ÷ [999.0] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] -÷ 0915 × 094D × 094D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (ConjunctLinkingScripts_LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinkingScripts_ConjunctLinker_ExtCccZwj) × [9.3] DEVANAGARI LETTER TA (ConjunctLinkingScripts_LinkingConsonant) ÷ [0.3] +÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 200D ÷ 1F1E7 × 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 × 1F1E9 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER D (RI) ÷ [999.0] LATIN SMALL LETTER B (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0061 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] LATIN SMALL LETTER B (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0061 × 0903 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] LATIN SMALL LETTER B (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0061 ÷ 0600 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) × [9.2] LATIN SMALL LETTER B (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 0061 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 0061 × 1F3FF ÷ 1F476 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] BABY (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ConjunctExtendermConjunctLinker) × [9.0] COMBINING DIAERESIS (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) × [11.0] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 1F6D1 × 200D × 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 0061 × 200D ÷ 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 2701 × 200D ÷ 2701 ÷ # ÷ [0.2] UPPER BLADE SCISSORS (XXmLinkingConsonantmExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] UPPER BLADE SCISSORS (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0061 × 200D ÷ 2701 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] UPPER BLADE SCISSORS (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0915 ÷ 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) ÷ [999.0] DEVANAGARI LETTER TA (LinkingConsonant) ÷ [0.3] +÷ 0915 × 094D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.3] DEVANAGARI LETTER TA (LinkingConsonant) ÷ [0.3] +÷ 0915 × 094D × 094D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.3] DEVANAGARI LETTER TA (LinkingConsonant) ÷ [0.3] +÷ 0915 × 094D × 200D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) × [9.3] DEVANAGARI LETTER TA (LinkingConsonant) ÷ [0.3] +÷ 0915 × 093C × 200D × 094D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctExtendermConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.3] DEVANAGARI LETTER TA (LinkingConsonant) ÷ [0.3] +÷ 0915 × 093C × 094D × 200D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] DEVANAGARI SIGN NUKTA (Extend_ConjunctExtendermConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] ZERO WIDTH JOINER (ZWJ) × [9.3] DEVANAGARI LETTER TA (LinkingConsonant) ÷ [0.3] +÷ 0915 × 094D × 0924 × 094D × 092F ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.3] DEVANAGARI LETTER TA (LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.3] DEVANAGARI LETTER YA (LinkingConsonant) ÷ [0.3] +÷ 0915 × 094D ÷ 0061 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) ÷ [0.3] +÷ 0061 × 094D ÷ 0924 ÷ # ÷ [0.2] LATIN SMALL LETTER A (XXmLinkingConsonantmExtPict) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] DEVANAGARI LETTER TA (LinkingConsonant) ÷ [0.3] +÷ 003F × 094D ÷ 0924 ÷ # ÷ [0.2] QUESTION MARK (XXmLinkingConsonantmExtPict) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) ÷ [999.0] DEVANAGARI LETTER TA (LinkingConsonant) ÷ [0.3] +÷ 0915 × 094D × 094D × 0924 ÷ # ÷ [0.2] DEVANAGARI LETTER KA (LinkingConsonant) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.0] DEVANAGARI SIGN VIRAMA (Extend_ConjunctLinker) × [9.3] DEVANAGARI LETTER TA (LinkingConsonant) ÷ [0.3] +÷ 0AB8 × 0AFB × 0ACD × 0AB8 × 0AFB ÷ # ÷ [0.2] GUJARATI LETTER SA (LinkingConsonant) × [9.0] GUJARATI SIGN SHADDA (Extend_ConjunctExtendermConjunctLinker) × [9.0] GUJARATI SIGN VIRAMA (Extend_ConjunctLinker) × [9.3] GUJARATI LETTER SA (LinkingConsonant) × [9.0] GUJARATI SIGN SHADDA (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 1019 × 1039 × 1018 ÷ 102C × 1037 ÷ # ÷ [0.2] MYANMAR LETTER MA (LinkingConsonant) × [9.0] MYANMAR SIGN VIRAMA (Extend_ConjunctLinker) × [9.3] MYANMAR LETTER BHA (LinkingConsonant) ÷ [999.0] MYANMAR VOWEL SIGN AA (XXmLinkingConsonantmExtPict) × [9.0] MYANMAR SIGN DOT BELOW (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 1004 × 103A × 1039 × 1011 × 1039 × 1011 ÷ # ÷ [0.2] MYANMAR LETTER NGA (LinkingConsonant) × [9.0] MYANMAR SIGN ASAT (Extend_ConjunctExtendermConjunctLinker) × [9.0] MYANMAR SIGN VIRAMA (Extend_ConjunctLinker) × [9.3] MYANMAR LETTER THA (LinkingConsonant) × [9.0] MYANMAR SIGN VIRAMA (Extend_ConjunctLinker) × [9.3] MYANMAR LETTER THA (LinkingConsonant) ÷ [0.3] +÷ 1B12 × 1B01 ÷ 1B32 × 1B44 × 1B2F ÷ 1B32 × 1B44 × 1B22 × 1B44 × 1B2C ÷ 1B32 × 1B44 × 1B22 × 1B38 ÷ # ÷ [0.2] BALINESE LETTER OKARA TEDUNG (XXmLinkingConsonantmExtPict) × [9.0] BALINESE SIGN ULU CANDRA (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] BALINESE LETTER SA (LinkingConsonant) × [9.0] BALINESE ADEG ADEG (Extend_ConjunctLinker) × [9.3] BALINESE LETTER WA (LinkingConsonant) ÷ [999.0] BALINESE LETTER SA (LinkingConsonant) × [9.0] BALINESE ADEG ADEG (Extend_ConjunctLinker) × [9.3] BALINESE LETTER TA (LinkingConsonant) × [9.0] BALINESE ADEG ADEG (Extend_ConjunctLinker) × [9.3] BALINESE LETTER YA (LinkingConsonant) ÷ [999.0] BALINESE LETTER SA (LinkingConsonant) × [9.0] BALINESE ADEG ADEG (Extend_ConjunctLinker) × [9.3] BALINESE LETTER TA (LinkingConsonant) × [9.0] BALINESE VOWEL SIGN SUKU (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 179F × 17D2 × 178F × 17D2 × 179A × 17B8 ÷ # ÷ [0.2] KHMER LETTER SA (LinkingConsonant) × [9.0] KHMER SIGN COENG (Extend_ConjunctLinker) × [9.3] KHMER LETTER TA (LinkingConsonant) × [9.0] KHMER SIGN COENG (Extend_ConjunctLinker) × [9.3] KHMER LETTER RO (LinkingConsonant) × [9.0] KHMER VOWEL SIGN II (Extend_ConjunctExtendermConjunctLinker) ÷ [0.3] +÷ 1B26 ÷ 1B17 × 1B44 × 1B13 ÷ # ÷ [0.2] BALINESE LETTER NA (LinkingConsonant) ÷ [999.0] BALINESE LETTER NGA (LinkingConsonant) × [9.0] BALINESE ADEG ADEG (Extend_ConjunctLinker) × [9.3] BALINESE LETTER KA (LinkingConsonant) ÷ [0.3] +÷ 1B27 ÷ 1B13 × 1B44 × 1B0B ÷ 1B0B × 1B04 ÷ # ÷ [0.2] BALINESE LETTER PA (LinkingConsonant) ÷ [999.0] BALINESE LETTER KA (LinkingConsonant) × [9.0] BALINESE ADEG ADEG (Extend_ConjunctLinker) × [9.3] BALINESE LETTER RA REPA (LinkingConsonant) ÷ [999.0] BALINESE LETTER RA REPA (LinkingConsonant) × [9.1] BALINESE SIGN BISAH (SpacingMark) ÷ [0.3] +÷ 1795 × 17D2 × 17AF ÷ 1798 ÷ # ÷ [0.2] KHMER LETTER PHA (LinkingConsonant) × [9.0] KHMER SIGN COENG (Extend_ConjunctLinker) × [9.3] KHMER INDEPENDENT VOWEL QE (LinkingConsonant) ÷ [999.0] KHMER LETTER MO (LinkingConsonant) ÷ [0.3] +÷ 17A0 × 17D2 × 17AB ÷ 1791 × 17D0 ÷ 1799 ÷ # ÷ [0.2] KHMER LETTER HA (LinkingConsonant) × [9.0] KHMER SIGN COENG (Extend_ConjunctLinker) × [9.3] KHMER INDEPENDENT VOWEL RY (LinkingConsonant) ÷ [999.0] KHMER LETTER TO (LinkingConsonant) × [9.0] KHMER SIGN SAMYOK SANNYA (Extend_ConjunctExtendermConjunctLinker) ÷ [999.0] KHMER LETTER YO (LinkingConsonant) ÷ [0.3] # -# Lines: 1093 +# Lines: 766 # # EOF diff --git a/src/java.base/share/data/unicodedata/emoji/emoji-data.txt b/src/java.base/share/data/unicodedata/emoji/emoji-data.txt index 12f83273cf5..450252c4df3 100644 --- a/src/java.base/share/data/unicodedata/emoji/emoji-data.txt +++ b/src/java.base/share/data/unicodedata/emoji/emoji-data.txt @@ -1,11 +1,11 @@ # emoji-data.txt -# Date: 2024-05-01, 21:25:24 GMT -# Copyright (c) 2024 Unicode, Inc. +# Date: 2025-07-25, 17:54:31 GMT +# © 2025 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. # For terms of use and license, see https://www.unicode.org/terms_of_use.html # # Emoji Data for UTS #51 -# Used with Emoji Version 16.0 and subsequent minor revisions (if any) +# Version: 17.0 # # For documentation and usage, see https://www.unicode.org/reports/tr51 # @@ -340,6 +340,7 @@ 1F6D1..1F6D2 ; Emoji # E3.0 [2] (🛑..🛒) stop sign..shopping cart 1F6D5 ; Emoji # E12.0 [1] (🛕) hindu temple 1F6D6..1F6D7 ; Emoji # E13.0 [2] (🛖..🛗) hut..elevator +1F6D8 ; Emoji # E17.0 [1] (🛘) landslide 1F6DC ; Emoji # E15.0 [1] (🛜) wireless 1F6DD..1F6DF ; Emoji # E14.0 [3] (🛝..🛟) playground slide..ring buoy 1F6E0..1F6E5 ; Emoji # E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat @@ -408,6 +409,8 @@ 1FA83..1FA86 ; Emoji # E13.0 [4] (🪃..🪆) boomerang..nesting dolls 1FA87..1FA88 ; Emoji # E15.0 [2] (🪇..🪈) maracas..flute 1FA89 ; Emoji # E16.0 [1] (🪉) harp +1FA8A ; Emoji # E17.0 [1] (🪊) trombone +1FA8E ; Emoji # E17.0 [1] (🪎) treasure chest 1FA8F ; Emoji # E16.0 [1] (🪏) shovel 1FA90..1FA95 ; Emoji # E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Emoji # E13.0 [19] (🪖..🪨) military helmet..rock @@ -421,6 +424,8 @@ 1FAC0..1FAC2 ; Emoji # E13.0 [3] (🫀..🫂) anatomical heart..people hugging 1FAC3..1FAC5 ; Emoji # E14.0 [3] (🫃..🫅) pregnant man..person with crown 1FAC6 ; Emoji # E16.0 [1] (🫆) fingerprint +1FAC8 ; Emoji # E17.0 [1] (🫈) hairy creature +1FACD ; Emoji # E17.0 [1] (🫍) orca 1FACE..1FACF ; Emoji # E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Emoji # E13.0 [7] (🫐..🫖) blueberries..teapot 1FAD7..1FAD9 ; Emoji # E14.0 [3] (🫗..🫙) pouring liquid..jar @@ -430,10 +435,12 @@ 1FAE0..1FAE7 ; Emoji # E14.0 [8] (🫠..🫧) melting face..bubbles 1FAE8 ; Emoji # E15.0 [1] (🫨) shaking face 1FAE9 ; Emoji # E16.0 [1] (🫩) face with bags under eyes +1FAEA ; Emoji # E17.0 [1] (🫪) distorted face +1FAEF ; Emoji # E17.0 [1] (🫯) fight cloud 1FAF0..1FAF6 ; Emoji # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands 1FAF7..1FAF8 ; Emoji # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand -# Total elements: 1431 +# Total elements: 1438 # ================================================ @@ -640,6 +647,7 @@ 1F6D1..1F6D2 ; Emoji_Presentation # E3.0 [2] (🛑..🛒) stop sign..shopping cart 1F6D5 ; Emoji_Presentation # E12.0 [1] (🛕) hindu temple 1F6D6..1F6D7 ; Emoji_Presentation # E13.0 [2] (🛖..🛗) hut..elevator +1F6D8 ; Emoji_Presentation # E17.0 [1] (🛘) landslide 1F6DC ; Emoji_Presentation # E15.0 [1] (🛜) wireless 1F6DD..1F6DF ; Emoji_Presentation # E14.0 [3] (🛝..🛟) playground slide..ring buoy 1F6EB..1F6EC ; Emoji_Presentation # E1.0 [2] (🛫..🛬) airplane departure..airplane arrival @@ -704,6 +712,8 @@ 1FA83..1FA86 ; Emoji_Presentation # E13.0 [4] (🪃..🪆) boomerang..nesting dolls 1FA87..1FA88 ; Emoji_Presentation # E15.0 [2] (🪇..🪈) maracas..flute 1FA89 ; Emoji_Presentation # E16.0 [1] (🪉) harp +1FA8A ; Emoji_Presentation # E17.0 [1] (🪊) trombone +1FA8E ; Emoji_Presentation # E17.0 [1] (🪎) treasure chest 1FA8F ; Emoji_Presentation # E16.0 [1] (🪏) shovel 1FA90..1FA95 ; Emoji_Presentation # E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Emoji_Presentation # E13.0 [19] (🪖..🪨) military helmet..rock @@ -717,6 +727,8 @@ 1FAC0..1FAC2 ; Emoji_Presentation # E13.0 [3] (🫀..🫂) anatomical heart..people hugging 1FAC3..1FAC5 ; Emoji_Presentation # E14.0 [3] (🫃..🫅) pregnant man..person with crown 1FAC6 ; Emoji_Presentation # E16.0 [1] (🫆) fingerprint +1FAC8 ; Emoji_Presentation # E17.0 [1] (🫈) hairy creature +1FACD ; Emoji_Presentation # E17.0 [1] (🫍) orca 1FACE..1FACF ; Emoji_Presentation # E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Emoji_Presentation # E13.0 [7] (🫐..🫖) blueberries..teapot 1FAD7..1FAD9 ; Emoji_Presentation # E14.0 [3] (🫗..🫙) pouring liquid..jar @@ -726,10 +738,12 @@ 1FAE0..1FAE7 ; Emoji_Presentation # E14.0 [8] (🫠..🫧) melting face..bubbles 1FAE8 ; Emoji_Presentation # E15.0 [1] (🫨) shaking face 1FAE9 ; Emoji_Presentation # E16.0 [1] (🫩) face with bags under eyes +1FAEA ; Emoji_Presentation # E17.0 [1] (🫪) distorted face +1FAEF ; Emoji_Presentation # E17.0 [1] (🫯) fight cloud 1FAF0..1FAF6 ; Emoji_Presentation # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands 1FAF7..1FAF8 ; Emoji_Presentation # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand -# Total elements: 1212 +# Total elements: 1219 # ================================================ @@ -827,7 +841,6 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 21A9..21AA ; Extended_Pictographic# E0.6 [2] (↩️..↪️) right arrow curving left..left arrow curving right 231A..231B ; Extended_Pictographic# E0.6 [2] (⌚..⌛) watch..hourglass done 2328 ; Extended_Pictographic# E1.0 [1] (⌨️) keyboard -2388 ; Extended_Pictographic# E0.0 [1] (⎈) HELM SYMBOL 23CF ; Extended_Pictographic# E1.0 [1] (⏏️) eject button 23E9..23EC ; Extended_Pictographic# E0.6 [4] (⏩..⏬) fast-forward button..fast down button 23ED..23EE ; Extended_Pictographic# E0.7 [2] (⏭️..⏮️) next track button..last track button @@ -844,106 +857,63 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 2600..2601 ; Extended_Pictographic# E0.6 [2] (☀️..☁️) sun..cloud 2602..2603 ; Extended_Pictographic# E0.7 [2] (☂️..☃️) umbrella..snowman 2604 ; Extended_Pictographic# E1.0 [1] (☄️) comet -2605 ; Extended_Pictographic# E0.0 [1] (★) BLACK STAR -2607..260D ; Extended_Pictographic# E0.0 [7] (☇..☍) LIGHTNING..OPPOSITION 260E ; Extended_Pictographic# E0.6 [1] (☎️) telephone -260F..2610 ; Extended_Pictographic# E0.0 [2] (☏..☐) WHITE TELEPHONE..BALLOT BOX 2611 ; Extended_Pictographic# E0.6 [1] (☑️) check box with check -2612 ; Extended_Pictographic# E0.0 [1] (☒) BALLOT BOX WITH X 2614..2615 ; Extended_Pictographic# E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage -2616..2617 ; Extended_Pictographic# E0.0 [2] (☖..☗) WHITE SHOGI PIECE..BLACK SHOGI PIECE 2618 ; Extended_Pictographic# E1.0 [1] (☘️) shamrock -2619..261C ; Extended_Pictographic# E0.0 [4] (☙..☜) REVERSED ROTATED FLORAL HEART BULLET..WHITE LEFT POINTING INDEX 261D ; Extended_Pictographic# E0.6 [1] (☝️) index pointing up -261E..261F ; Extended_Pictographic# E0.0 [2] (☞..☟) WHITE RIGHT POINTING INDEX..WHITE DOWN POINTING INDEX 2620 ; Extended_Pictographic# E1.0 [1] (☠️) skull and crossbones -2621 ; Extended_Pictographic# E0.0 [1] (☡) CAUTION SIGN 2622..2623 ; Extended_Pictographic# E1.0 [2] (☢️..☣️) radioactive..biohazard -2624..2625 ; Extended_Pictographic# E0.0 [2] (☤..☥) CADUCEUS..ANKH 2626 ; Extended_Pictographic# E1.0 [1] (☦️) orthodox cross -2627..2629 ; Extended_Pictographic# E0.0 [3] (☧..☩) CHI RHO..CROSS OF JERUSALEM 262A ; Extended_Pictographic# E0.7 [1] (☪️) star and crescent -262B..262D ; Extended_Pictographic# E0.0 [3] (☫..☭) FARSI SYMBOL..HAMMER AND SICKLE 262E ; Extended_Pictographic# E1.0 [1] (☮️) peace symbol 262F ; Extended_Pictographic# E0.7 [1] (☯️) yin yang -2630..2637 ; Extended_Pictographic# E0.0 [8] (☰..☷) TRIGRAM FOR HEAVEN..TRIGRAM FOR EARTH 2638..2639 ; Extended_Pictographic# E0.7 [2] (☸️..☹️) wheel of dharma..frowning face 263A ; Extended_Pictographic# E0.6 [1] (☺️) smiling face -263B..263F ; Extended_Pictographic# E0.0 [5] (☻..☿) BLACK SMILING FACE..MERCURY 2640 ; Extended_Pictographic# E4.0 [1] (♀️) female sign -2641 ; Extended_Pictographic# E0.0 [1] (♁) EARTH 2642 ; Extended_Pictographic# E4.0 [1] (♂️) male sign -2643..2647 ; Extended_Pictographic# E0.0 [5] (♃..♇) JUPITER..PLUTO 2648..2653 ; Extended_Pictographic# E0.6 [12] (♈..♓) Aries..Pisces -2654..265E ; Extended_Pictographic# E0.0 [11] (♔..♞) WHITE CHESS KING..BLACK CHESS KNIGHT 265F ; Extended_Pictographic# E11.0 [1] (♟️) chess pawn 2660 ; Extended_Pictographic# E0.6 [1] (♠️) spade suit -2661..2662 ; Extended_Pictographic# E0.0 [2] (♡..♢) WHITE HEART SUIT..WHITE DIAMOND SUIT 2663 ; Extended_Pictographic# E0.6 [1] (♣️) club suit -2664 ; Extended_Pictographic# E0.0 [1] (♤) WHITE SPADE SUIT 2665..2666 ; Extended_Pictographic# E0.6 [2] (♥️..♦️) heart suit..diamond suit -2667 ; Extended_Pictographic# E0.0 [1] (♧) WHITE CLUB SUIT 2668 ; Extended_Pictographic# E0.6 [1] (♨️) hot springs -2669..267A ; Extended_Pictographic# E0.0 [18] (♩..♺) QUARTER NOTE..RECYCLING SYMBOL FOR GENERIC MATERIALS 267B ; Extended_Pictographic# E0.6 [1] (♻️) recycling symbol -267C..267D ; Extended_Pictographic# E0.0 [2] (♼..♽) RECYCLED PAPER SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL 267E ; Extended_Pictographic# E11.0 [1] (♾️) infinity 267F ; Extended_Pictographic# E0.6 [1] (♿) wheelchair symbol -2680..2685 ; Extended_Pictographic# E0.0 [6] (⚀..⚅) DIE FACE-1..DIE FACE-6 -2690..2691 ; Extended_Pictographic# E0.0 [2] (⚐..⚑) WHITE FLAG..BLACK FLAG 2692 ; Extended_Pictographic# E1.0 [1] (⚒️) hammer and pick 2693 ; Extended_Pictographic# E0.6 [1] (⚓) anchor 2694 ; Extended_Pictographic# E1.0 [1] (⚔️) crossed swords 2695 ; Extended_Pictographic# E4.0 [1] (⚕️) medical symbol 2696..2697 ; Extended_Pictographic# E1.0 [2] (⚖️..⚗️) balance scale..alembic -2698 ; Extended_Pictographic# E0.0 [1] (⚘) FLOWER 2699 ; Extended_Pictographic# E1.0 [1] (⚙️) gear -269A ; Extended_Pictographic# E0.0 [1] (⚚) STAFF OF HERMES 269B..269C ; Extended_Pictographic# E1.0 [2] (⚛️..⚜️) atom symbol..fleur-de-lis -269D..269F ; Extended_Pictographic# E0.0 [3] (⚝..⚟) OUTLINED WHITE STAR..THREE LINES CONVERGING LEFT 26A0..26A1 ; Extended_Pictographic# E0.6 [2] (⚠️..⚡) warning..high voltage -26A2..26A6 ; Extended_Pictographic# E0.0 [5] (⚢..⚦) DOUBLED FEMALE SIGN..MALE WITH STROKE SIGN 26A7 ; Extended_Pictographic# E13.0 [1] (⚧️) transgender symbol -26A8..26A9 ; Extended_Pictographic# E0.0 [2] (⚨..⚩) VERTICAL MALE WITH STROKE SIGN..HORIZONTAL MALE WITH STROKE SIGN 26AA..26AB ; Extended_Pictographic# E0.6 [2] (⚪..⚫) white circle..black circle -26AC..26AF ; Extended_Pictographic# E0.0 [4] (⚬..⚯) MEDIUM SMALL WHITE CIRCLE..UNMARRIED PARTNERSHIP SYMBOL 26B0..26B1 ; Extended_Pictographic# E1.0 [2] (⚰️..⚱️) coffin..funeral urn -26B2..26BC ; Extended_Pictographic# E0.0 [11] (⚲..⚼) NEUTER..SESQUIQUADRATE 26BD..26BE ; Extended_Pictographic# E0.6 [2] (⚽..⚾) soccer ball..baseball -26BF..26C3 ; Extended_Pictographic# E0.0 [5] (⚿..⛃) SQUARED KEY..BLACK DRAUGHTS KING 26C4..26C5 ; Extended_Pictographic# E0.6 [2] (⛄..⛅) snowman without snow..sun behind cloud -26C6..26C7 ; Extended_Pictographic# E0.0 [2] (⛆..⛇) RAIN..BLACK SNOWMAN 26C8 ; Extended_Pictographic# E0.7 [1] (⛈️) cloud with lightning and rain -26C9..26CD ; Extended_Pictographic# E0.0 [5] (⛉..⛍) TURNED WHITE SHOGI PIECE..DISABLED CAR 26CE ; Extended_Pictographic# E0.6 [1] (⛎) Ophiuchus 26CF ; Extended_Pictographic# E0.7 [1] (⛏️) pick -26D0 ; Extended_Pictographic# E0.0 [1] (⛐) CAR SLIDING 26D1 ; Extended_Pictographic# E0.7 [1] (⛑️) rescue worker’s helmet -26D2 ; Extended_Pictographic# E0.0 [1] (⛒) CIRCLED CROSSING LANES 26D3 ; Extended_Pictographic# E0.7 [1] (⛓️) chains 26D4 ; Extended_Pictographic# E0.6 [1] (⛔) no entry -26D5..26E8 ; Extended_Pictographic# E0.0 [20] (⛕..⛨) ALTERNATE ONE-WAY LEFT WAY TRAFFIC..BLACK CROSS ON SHIELD 26E9 ; Extended_Pictographic# E0.7 [1] (⛩️) shinto shrine 26EA ; Extended_Pictographic# E0.6 [1] (⛪) church -26EB..26EF ; Extended_Pictographic# E0.0 [5] (⛫..⛯) CASTLE..MAP SYMBOL FOR LIGHTHOUSE 26F0..26F1 ; Extended_Pictographic# E0.7 [2] (⛰️..⛱️) mountain..umbrella on ground 26F2..26F3 ; Extended_Pictographic# E0.6 [2] (⛲..⛳) fountain..flag in hole 26F4 ; Extended_Pictographic# E0.7 [1] (⛴️) ferry 26F5 ; Extended_Pictographic# E0.6 [1] (⛵) sailboat -26F6 ; Extended_Pictographic# E0.0 [1] (⛶) SQUARE FOUR CORNERS 26F7..26F9 ; Extended_Pictographic# E0.7 [3] (⛷️..⛹️) skier..person bouncing ball 26FA ; Extended_Pictographic# E0.6 [1] (⛺) tent -26FB..26FC ; Extended_Pictographic# E0.0 [2] (⛻..⛼) JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL 26FD ; Extended_Pictographic# E0.6 [1] (⛽) fuel pump -26FE..2701 ; Extended_Pictographic# E0.0 [4] (⛾..✁) CUP ON BLACK SQUARE..UPPER BLADE SCISSORS 2702 ; Extended_Pictographic# E0.6 [1] (✂️) scissors -2703..2704 ; Extended_Pictographic# E0.0 [2] (✃..✄) LOWER BLADE SCISSORS..WHITE SCISSORS 2705 ; Extended_Pictographic# E0.6 [1] (✅) check mark button 2708..270C ; Extended_Pictographic# E0.6 [5] (✈️..✌️) airplane..victory hand 270D ; Extended_Pictographic# E0.7 [1] (✍️) writing hand -270E ; Extended_Pictographic# E0.0 [1] (✎) LOWER RIGHT PENCIL 270F ; Extended_Pictographic# E0.6 [1] (✏️) pencil -2710..2711 ; Extended_Pictographic# E0.0 [2] (✐..✑) UPPER RIGHT PENCIL..WHITE NIB 2712 ; Extended_Pictographic# E0.6 [1] (✒️) black nib 2714 ; Extended_Pictographic# E0.6 [1] (✔️) check mark 2716 ; Extended_Pictographic# E0.6 [1] (✖️) multiply @@ -959,7 +929,6 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 2757 ; Extended_Pictographic# E0.6 [1] (❗) red exclamation mark 2763 ; Extended_Pictographic# E1.0 [1] (❣️) heart exclamation 2764 ; Extended_Pictographic# E0.6 [1] (❤️) red heart -2765..2767 ; Extended_Pictographic# E0.0 [3] (❥..❧) ROTATED HEAVY BLACK HEART BULLET..ROTATED FLORAL HEART BULLET 2795..2797 ; Extended_Pictographic# E0.6 [3] (➕..➗) plus..divide 27A1 ; Extended_Pictographic# E0.6 [1] (➡️) right arrow 27B0 ; Extended_Pictographic# E0.6 [1] (➰) curly loop @@ -973,19 +942,19 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 303D ; Extended_Pictographic# E0.6 [1] (〽️) part alternation mark 3297 ; Extended_Pictographic# E0.6 [1] (㊗️) Japanese “congratulations” button 3299 ; Extended_Pictographic# E0.6 [1] (㊙️) Japanese “secret” button -1F000..1F003 ; Extended_Pictographic# E0.0 [4] (🀀..🀃) MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND 1F004 ; Extended_Pictographic# E0.6 [1] (🀄) mahjong red dragon -1F005..1F0CE ; Extended_Pictographic# E0.0 [202] (🀅..🃎) MAHJONG TILE GREEN DRAGON..PLAYING CARD KING OF DIAMONDS +1F02C..1F02F ; Extended_Pictographic# E0.0 [4] (🀬..🀯) .. +1F094..1F09F ; Extended_Pictographic# E0.0 [12] (🂔..🂟) .. +1F0AF..1F0B0 ; Extended_Pictographic# E0.0 [2] (🂯..🂰) .. +1F0C0 ; Extended_Pictographic# E0.0 [1] (🃀) 1F0CF ; Extended_Pictographic# E0.6 [1] (🃏) joker -1F0D0..1F0FF ; Extended_Pictographic# E0.0 [48] (🃐..🃿) .. -1F10D..1F10F ; Extended_Pictographic# E0.0 [3] (🄍..🄏) CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH -1F12F ; Extended_Pictographic# E0.0 [1] (🄯) COPYLEFT SYMBOL -1F16C..1F16F ; Extended_Pictographic# E0.0 [4] (🅬..🅯) RAISED MR SIGN..CIRCLED HUMAN FIGURE +1F0D0 ; Extended_Pictographic# E0.0 [1] (🃐) +1F0F6..1F0FF ; Extended_Pictographic# E0.0 [10] (🃶..🃿) .. 1F170..1F171 ; Extended_Pictographic# E0.6 [2] (🅰️..🅱️) A button (blood type)..B button (blood type) 1F17E..1F17F ; Extended_Pictographic# E0.6 [2] (🅾️..🅿️) O button (blood type)..P button 1F18E ; Extended_Pictographic# E0.6 [1] (🆎) AB button (blood type) 1F191..1F19A ; Extended_Pictographic# E0.6 [10] (🆑..🆚) CL button..VS button -1F1AD..1F1E5 ; Extended_Pictographic# E0.0 [57] (🆭..🇥) MASK WORK SYMBOL.. +1F1AE..1F1E5 ; Extended_Pictographic# E0.0 [56] (🆮..🇥) .. 1F201..1F202 ; Extended_Pictographic# E0.6 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button 1F203..1F20F ; Extended_Pictographic# E0.0 [13] (🈃..🈏) .. 1F21A ; Extended_Pictographic# E0.6 [1] (🈚) Japanese “free of charge” button @@ -994,7 +963,8 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F23C..1F23F ; Extended_Pictographic# E0.0 [4] (🈼..🈿) .. 1F249..1F24F ; Extended_Pictographic# E0.0 [7] (🉉..🉏) .. 1F250..1F251 ; Extended_Pictographic# E0.6 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button -1F252..1F2FF ; Extended_Pictographic# E0.0 [174] (🉒..🋿) .. +1F252..1F25F ; Extended_Pictographic# E0.0 [14] (🉒..🉟) .. +1F266..1F2FF ; Extended_Pictographic# E0.0 [154] (🉦..🋿) .. 1F300..1F30C ; Extended_Pictographic# E0.6 [13] (🌀..🌌) cyclone..milky way 1F30D..1F30E ; Extended_Pictographic# E0.7 [2] (🌍..🌎) globe showing Europe-Africa..globe showing Americas 1F30F ; Extended_Pictographic# E0.6 [1] (🌏) globe showing Asia-Australia @@ -1010,7 +980,6 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F31D..1F31E ; Extended_Pictographic# E1.0 [2] (🌝..🌞) full moon face..sun with face 1F31F..1F320 ; Extended_Pictographic# E0.6 [2] (🌟..🌠) glowing star..shooting star 1F321 ; Extended_Pictographic# E0.7 [1] (🌡️) thermometer -1F322..1F323 ; Extended_Pictographic# E0.0 [2] (🌢..🌣) BLACK DROPLET..WHITE SUN 1F324..1F32C ; Extended_Pictographic# E0.7 [9] (🌤️..🌬️) sun behind small cloud..wind face 1F32D..1F32F ; Extended_Pictographic# E1.0 [3] (🌭..🌯) hot dog..burrito 1F330..1F331 ; Extended_Pictographic# E0.6 [2] (🌰..🌱) chestnut..seedling @@ -1026,11 +995,8 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F37D ; Extended_Pictographic# E0.7 [1] (🍽️) fork and knife with plate 1F37E..1F37F ; Extended_Pictographic# E1.0 [2] (🍾..🍿) bottle with popping cork..popcorn 1F380..1F393 ; Extended_Pictographic# E0.6 [20] (🎀..🎓) ribbon..graduation cap -1F394..1F395 ; Extended_Pictographic# E0.0 [2] (🎔..🎕) HEART WITH TIP ON THE LEFT..BOUQUET OF FLOWERS 1F396..1F397 ; Extended_Pictographic# E0.7 [2] (🎖️..🎗️) military medal..reminder ribbon -1F398 ; Extended_Pictographic# E0.0 [1] (🎘) MUSICAL KEYBOARD WITH JACKS 1F399..1F39B ; Extended_Pictographic# E0.7 [3] (🎙️..🎛️) studio microphone..control knobs -1F39C..1F39D ; Extended_Pictographic# E0.0 [2] (🎜..🎝) BEAMED ASCENDING MUSICAL NOTES..BEAMED DESCENDING MUSICAL NOTES 1F39E..1F39F ; Extended_Pictographic# E0.7 [2] (🎞️..🎟️) film frames..admission tickets 1F3A0..1F3C4 ; Extended_Pictographic# E0.6 [37] (🎠..🏄) carousel horse..person surfing 1F3C5 ; Extended_Pictographic# E1.0 [1] (🏅) sports medal @@ -1045,11 +1011,9 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F3E0..1F3E3 ; Extended_Pictographic# E0.6 [4] (🏠..🏣) house..Japanese post office 1F3E4 ; Extended_Pictographic# E1.0 [1] (🏤) post office 1F3E5..1F3F0 ; Extended_Pictographic# E0.6 [12] (🏥..🏰) hospital..castle -1F3F1..1F3F2 ; Extended_Pictographic# E0.0 [2] (🏱..🏲) WHITE PENNANT..BLACK PENNANT 1F3F3 ; Extended_Pictographic# E0.7 [1] (🏳️) white flag 1F3F4 ; Extended_Pictographic# E1.0 [1] (🏴) black flag 1F3F5 ; Extended_Pictographic# E0.7 [1] (🏵️) rosette -1F3F6 ; Extended_Pictographic# E0.0 [1] (🏶) BLACK ROSETTE 1F3F7 ; Extended_Pictographic# E0.7 [1] (🏷️) label 1F3F8..1F3FA ; Extended_Pictographic# E1.0 [3] (🏸..🏺) badminton..amphora 1F400..1F407 ; Extended_Pictographic# E1.0 [8] (🐀..🐇) rat..rabbit @@ -1086,7 +1050,6 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F4F8 ; Extended_Pictographic# E1.0 [1] (📸) camera with flash 1F4F9..1F4FC ; Extended_Pictographic# E0.6 [4] (📹..📼) video camera..videocassette 1F4FD ; Extended_Pictographic# E0.7 [1] (📽️) film projector -1F4FE ; Extended_Pictographic# E0.0 [1] (📾) PORTABLE STEREO 1F4FF..1F502 ; Extended_Pictographic# E1.0 [4] (📿..🔂) prayer beads..repeat single button 1F503 ; Extended_Pictographic# E0.6 [1] (🔃) clockwise vertical arrows 1F504..1F507 ; Extended_Pictographic# E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker @@ -1097,51 +1060,30 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F516..1F52B ; Extended_Pictographic# E0.6 [22] (🔖..🔫) bookmark..water pistol 1F52C..1F52D ; Extended_Pictographic# E1.0 [2] (🔬..🔭) microscope..telescope 1F52E..1F53D ; Extended_Pictographic# E0.6 [16] (🔮..🔽) crystal ball..downwards button -1F546..1F548 ; Extended_Pictographic# E0.0 [3] (🕆..🕈) WHITE LATIN CROSS..CELTIC CROSS 1F549..1F54A ; Extended_Pictographic# E0.7 [2] (🕉️..🕊️) om..dove 1F54B..1F54E ; Extended_Pictographic# E1.0 [4] (🕋..🕎) kaaba..menorah -1F54F ; Extended_Pictographic# E0.0 [1] (🕏) BOWL OF HYGIEIA 1F550..1F55B ; Extended_Pictographic# E0.6 [12] (🕐..🕛) one o’clock..twelve o’clock 1F55C..1F567 ; Extended_Pictographic# E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty -1F568..1F56E ; Extended_Pictographic# E0.0 [7] (🕨..🕮) RIGHT SPEAKER..BOOK 1F56F..1F570 ; Extended_Pictographic# E0.7 [2] (🕯️..🕰️) candle..mantelpiece clock -1F571..1F572 ; Extended_Pictographic# E0.0 [2] (🕱..🕲) BLACK SKULL AND CROSSBONES..NO PIRACY 1F573..1F579 ; Extended_Pictographic# E0.7 [7] (🕳️..🕹️) hole..joystick 1F57A ; Extended_Pictographic# E3.0 [1] (🕺) man dancing -1F57B..1F586 ; Extended_Pictographic# E0.0 [12] (🕻..🖆) LEFT HAND TELEPHONE RECEIVER..PEN OVER STAMPED ENVELOPE 1F587 ; Extended_Pictographic# E0.7 [1] (🖇️) linked paperclips -1F588..1F589 ; Extended_Pictographic# E0.0 [2] (🖈..🖉) BLACK PUSHPIN..LOWER LEFT PENCIL 1F58A..1F58D ; Extended_Pictographic# E0.7 [4] (🖊️..🖍️) pen..crayon -1F58E..1F58F ; Extended_Pictographic# E0.0 [2] (🖎..🖏) LEFT WRITING HAND..TURNED OK HAND SIGN 1F590 ; Extended_Pictographic# E0.7 [1] (🖐️) hand with fingers splayed -1F591..1F594 ; Extended_Pictographic# E0.0 [4] (🖑..🖔) REVERSED RAISED HAND WITH FINGERS SPLAYED..REVERSED VICTORY HAND 1F595..1F596 ; Extended_Pictographic# E1.0 [2] (🖕..🖖) middle finger..vulcan salute -1F597..1F5A3 ; Extended_Pictographic# E0.0 [13] (🖗..🖣) WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX 1F5A4 ; Extended_Pictographic# E3.0 [1] (🖤) black heart 1F5A5 ; Extended_Pictographic# E0.7 [1] (🖥️) desktop computer -1F5A6..1F5A7 ; Extended_Pictographic# E0.0 [2] (🖦..🖧) KEYBOARD AND MOUSE..THREE NETWORKED COMPUTERS 1F5A8 ; Extended_Pictographic# E0.7 [1] (🖨️) printer -1F5A9..1F5B0 ; Extended_Pictographic# E0.0 [8] (🖩..🖰) POCKET CALCULATOR..TWO BUTTON MOUSE 1F5B1..1F5B2 ; Extended_Pictographic# E0.7 [2] (🖱️..🖲️) computer mouse..trackball -1F5B3..1F5BB ; Extended_Pictographic# E0.0 [9] (🖳..🖻) OLD PERSONAL COMPUTER..DOCUMENT WITH PICTURE 1F5BC ; Extended_Pictographic# E0.7 [1] (🖼️) framed picture -1F5BD..1F5C1 ; Extended_Pictographic# E0.0 [5] (🖽..🗁) FRAME WITH TILES..OPEN FOLDER 1F5C2..1F5C4 ; Extended_Pictographic# E0.7 [3] (🗂️..🗄️) card index dividers..file cabinet -1F5C5..1F5D0 ; Extended_Pictographic# E0.0 [12] (🗅..🗐) EMPTY NOTE..PAGES 1F5D1..1F5D3 ; Extended_Pictographic# E0.7 [3] (🗑️..🗓️) wastebasket..spiral calendar -1F5D4..1F5DB ; Extended_Pictographic# E0.0 [8] (🗔..🗛) DESKTOP WINDOW..DECREASE FONT SIZE SYMBOL 1F5DC..1F5DE ; Extended_Pictographic# E0.7 [3] (🗜️..🗞️) clamp..rolled-up newspaper -1F5DF..1F5E0 ; Extended_Pictographic# E0.0 [2] (🗟..🗠) PAGE WITH CIRCLED TEXT..STOCK CHART 1F5E1 ; Extended_Pictographic# E0.7 [1] (🗡️) dagger -1F5E2 ; Extended_Pictographic# E0.0 [1] (🗢) LIPS 1F5E3 ; Extended_Pictographic# E0.7 [1] (🗣️) speaking head -1F5E4..1F5E7 ; Extended_Pictographic# E0.0 [4] (🗤..🗧) THREE RAYS ABOVE..THREE RAYS RIGHT 1F5E8 ; Extended_Pictographic# E2.0 [1] (🗨️) left speech bubble -1F5E9..1F5EE ; Extended_Pictographic# E0.0 [6] (🗩..🗮) RIGHT SPEECH BUBBLE..LEFT ANGER BUBBLE 1F5EF ; Extended_Pictographic# E0.7 [1] (🗯️) right anger bubble -1F5F0..1F5F2 ; Extended_Pictographic# E0.0 [3] (🗰..🗲) MOOD BUBBLE..LIGHTNING MOOD 1F5F3 ; Extended_Pictographic# E0.7 [1] (🗳️) ballot box with ballot -1F5F4..1F5F9 ; Extended_Pictographic# E0.0 [6] (🗴..🗹) BALLOT SCRIPT X..BALLOT BOX WITH BOLD CHECK 1F5FA ; Extended_Pictographic# E0.7 [1] (🗺️) world map 1F5FB..1F5FF ; Extended_Pictographic# E0.6 [5] (🗻..🗿) mount fuji..moai 1F600 ; Extended_Pictographic# E1.0 [1] (😀) grinning face @@ -1210,26 +1152,22 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F6BF ; Extended_Pictographic# E1.0 [1] (🚿) shower 1F6C0 ; Extended_Pictographic# E0.6 [1] (🛀) person taking bath 1F6C1..1F6C5 ; Extended_Pictographic# E1.0 [5] (🛁..🛅) bathtub..left luggage -1F6C6..1F6CA ; Extended_Pictographic# E0.0 [5] (🛆..🛊) TRIANGLE WITH ROUNDED CORNERS..GIRLS SYMBOL 1F6CB ; Extended_Pictographic# E0.7 [1] (🛋️) couch and lamp 1F6CC ; Extended_Pictographic# E1.0 [1] (🛌) person in bed 1F6CD..1F6CF ; Extended_Pictographic# E0.7 [3] (🛍️..🛏️) shopping bags..bed 1F6D0 ; Extended_Pictographic# E1.0 [1] (🛐) place of worship 1F6D1..1F6D2 ; Extended_Pictographic# E3.0 [2] (🛑..🛒) stop sign..shopping cart -1F6D3..1F6D4 ; Extended_Pictographic# E0.0 [2] (🛓..🛔) STUPA..PAGODA 1F6D5 ; Extended_Pictographic# E12.0 [1] (🛕) hindu temple 1F6D6..1F6D7 ; Extended_Pictographic# E13.0 [2] (🛖..🛗) hut..elevator -1F6D8..1F6DB ; Extended_Pictographic# E0.0 [4] (🛘..🛛) .. +1F6D8 ; Extended_Pictographic# E17.0 [1] (🛘) landslide +1F6D9..1F6DB ; Extended_Pictographic# E0.0 [3] (🛙..🛛) .. 1F6DC ; Extended_Pictographic# E15.0 [1] (🛜) wireless 1F6DD..1F6DF ; Extended_Pictographic# E14.0 [3] (🛝..🛟) playground slide..ring buoy 1F6E0..1F6E5 ; Extended_Pictographic# E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat -1F6E6..1F6E8 ; Extended_Pictographic# E0.0 [3] (🛦..🛨) UP-POINTING MILITARY AIRPLANE..UP-POINTING SMALL AIRPLANE 1F6E9 ; Extended_Pictographic# E0.7 [1] (🛩️) small airplane -1F6EA ; Extended_Pictographic# E0.0 [1] (🛪) NORTHEAST-POINTING AIRPLANE 1F6EB..1F6EC ; Extended_Pictographic# E1.0 [2] (🛫..🛬) airplane departure..airplane arrival 1F6ED..1F6EF ; Extended_Pictographic# E0.0 [3] (🛭..🛯) .. 1F6F0 ; Extended_Pictographic# E0.7 [1] (🛰️) satellite -1F6F1..1F6F2 ; Extended_Pictographic# E0.0 [2] (🛱..🛲) ONCOMING FIRE ENGINE..DIESEL LOCOMOTIVE 1F6F3 ; Extended_Pictographic# E0.7 [1] (🛳️) passenger ship 1F6F4..1F6F6 ; Extended_Pictographic# E3.0 [3] (🛴..🛶) kick scooter..canoe 1F6F7..1F6F8 ; Extended_Pictographic# E5.0 [2] (🛷..🛸) sled..flying saucer @@ -1237,8 +1175,7 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F6FA ; Extended_Pictographic# E12.0 [1] (🛺) auto rickshaw 1F6FB..1F6FC ; Extended_Pictographic# E13.0 [2] (🛻..🛼) pickup truck..roller skate 1F6FD..1F6FF ; Extended_Pictographic# E0.0 [3] (🛽..🛿) .. -1F774..1F77F ; Extended_Pictographic# E0.0 [12] (🝴..🝿) LOT OF FORTUNE..ORCUS -1F7D5..1F7DF ; Extended_Pictographic# E0.0 [11] (🟕..🟟) CIRCLED TRIANGLE.. +1F7DA..1F7DF ; Extended_Pictographic# E0.0 [6] (🟚..🟟) .. 1F7E0..1F7EB ; Extended_Pictographic# E12.0 [12] (🟠..🟫) orange circle..brown square 1F7EC..1F7EF ; Extended_Pictographic# E0.0 [4] (🟬..🟯) .. 1F7F0 ; Extended_Pictographic# E14.0 [1] (🟰) heavy equals sign @@ -1247,7 +1184,10 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F848..1F84F ; Extended_Pictographic# E0.0 [8] (🡈..🡏) .. 1F85A..1F85F ; Extended_Pictographic# E0.0 [6] (🡚..🡟) .. 1F888..1F88F ; Extended_Pictographic# E0.0 [8] (🢈..🢏) .. -1F8AE..1F8FF ; Extended_Pictographic# E0.0 [82] (🢮..🣿) .. +1F8AE..1F8AF ; Extended_Pictographic# E0.0 [2] (🢮..🢯) .. +1F8BC..1F8BF ; Extended_Pictographic# E0.0 [4] (🢼..🢿) .. +1F8C2..1F8CF ; Extended_Pictographic# E0.0 [14] (🣂..🣏) .. +1F8D9..1F8FF ; Extended_Pictographic# E0.0 [39] (🣙..🣿) .. 1F90C ; Extended_Pictographic# E13.0 [1] (🤌) pinched fingers 1F90D..1F90F ; Extended_Pictographic# E12.0 [3] (🤍..🤏) white heart..pinching hand 1F910..1F918 ; Extended_Pictographic# E1.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns @@ -1293,7 +1233,8 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F9CD..1F9CF ; Extended_Pictographic# E12.0 [3] (🧍..🧏) person standing..deaf person 1F9D0..1F9E6 ; Extended_Pictographic# E5.0 [23] (🧐..🧦) face with monocle..socks 1F9E7..1F9FF ; Extended_Pictographic# E11.0 [25] (🧧..🧿) red envelope..nazar amulet -1FA00..1FA6F ; Extended_Pictographic# E0.0 [112] (🨀..🩯) NEUTRAL CHESS KING.. +1FA58..1FA5F ; Extended_Pictographic# E0.0 [8] (🩘..🩟) .. +1FA6E..1FA6F ; Extended_Pictographic# E0.0 [2] (🩮..🩯) .. 1FA70..1FA73 ; Extended_Pictographic# E12.0 [4] (🩰..🩳) ballet shoes..shorts 1FA74 ; Extended_Pictographic# E13.0 [1] (🩴) thong sandal 1FA75..1FA77 ; Extended_Pictographic# E15.0 [3] (🩵..🩷) light blue heart..pink heart @@ -1304,7 +1245,9 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1FA83..1FA86 ; Extended_Pictographic# E13.0 [4] (🪃..🪆) boomerang..nesting dolls 1FA87..1FA88 ; Extended_Pictographic# E15.0 [2] (🪇..🪈) maracas..flute 1FA89 ; Extended_Pictographic# E16.0 [1] (🪉) harp -1FA8A..1FA8E ; Extended_Pictographic# E0.0 [5] (🪊..🪎) .. +1FA8A ; Extended_Pictographic# E17.0 [1] (🪊) trombone +1FA8B..1FA8D ; Extended_Pictographic# E0.0 [3] (🪋..🪍) .. +1FA8E ; Extended_Pictographic# E17.0 [1] (🪎) treasure chest 1FA8F ; Extended_Pictographic# E16.0 [1] (🪏) shovel 1FA90..1FA95 ; Extended_Pictographic# E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Extended_Pictographic# E13.0 [19] (🪖..🪨) military helmet..rock @@ -1318,7 +1261,10 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1FAC0..1FAC2 ; Extended_Pictographic# E13.0 [3] (🫀..🫂) anatomical heart..people hugging 1FAC3..1FAC5 ; Extended_Pictographic# E14.0 [3] (🫃..🫅) pregnant man..person with crown 1FAC6 ; Extended_Pictographic# E16.0 [1] (🫆) fingerprint -1FAC7..1FACD ; Extended_Pictographic# E0.0 [7] (🫇..🫍) .. +1FAC7 ; Extended_Pictographic# E0.0 [1] (🫇) +1FAC8 ; Extended_Pictographic# E17.0 [1] (🫈) hairy creature +1FAC9..1FACC ; Extended_Pictographic# E0.0 [4] (🫉..🫌) .. +1FACD ; Extended_Pictographic# E17.0 [1] (🫍) orca 1FACE..1FACF ; Extended_Pictographic# E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Extended_Pictographic# E13.0 [7] (🫐..🫖) blueberries..teapot 1FAD7..1FAD9 ; Extended_Pictographic# E14.0 [3] (🫗..🫙) pouring liquid..jar @@ -1329,12 +1275,14 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1FAE0..1FAE7 ; Extended_Pictographic# E14.0 [8] (🫠..🫧) melting face..bubbles 1FAE8 ; Extended_Pictographic# E15.0 [1] (🫨) shaking face 1FAE9 ; Extended_Pictographic# E16.0 [1] (🫩) face with bags under eyes -1FAEA..1FAEF ; Extended_Pictographic# E0.0 [6] (🫪..🫯) .. +1FAEA ; Extended_Pictographic# E17.0 [1] (🫪) distorted face +1FAEB..1FAEE ; Extended_Pictographic# E0.0 [4] (🫫..🫮) .. +1FAEF ; Extended_Pictographic# E17.0 [1] (🫯) fight cloud 1FAF0..1FAF6 ; Extended_Pictographic# E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands 1FAF7..1FAF8 ; Extended_Pictographic# E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand 1FAF9..1FAFF ; Extended_Pictographic# E0.0 [7] (🫹..🫿) .. 1FC00..1FFFD ; Extended_Pictographic# E0.0[1022] (🰀..🿽) .. -# Total elements: 3537 +# Total elements: 2848 #EOF diff --git a/src/java.base/share/legal/icu.md b/src/java.base/share/legal/icu.md index e27193e10be..634fea70d92 100644 --- a/src/java.base/share/legal/icu.md +++ b/src/java.base/share/legal/icu.md @@ -1,4 +1,4 @@ -## International Components for Unicode (ICU4J) v76.1 +## International Components for Unicode (ICU4J) v78.1 ### ICU4J License ``` @@ -6,7 +6,7 @@ UNICODE LICENSE V3 COPYRIGHT AND PERMISSION NOTICE -Copyright © 2016-2024 Unicode, Inc. +Copyright © 2016-2025 Unicode, Inc. NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR diff --git a/src/java.base/share/legal/unicode.md b/src/java.base/share/legal/unicode.md index 8bd2ed8bd13..a1009c70c1c 100644 --- a/src/java.base/share/legal/unicode.md +++ b/src/java.base/share/legal/unicode.md @@ -1,4 +1,4 @@ -## The Unicode Standard, Unicode Character Database, Version 16.0.0 +## The Unicode Standard, Unicode Character Database, Version 17.0.0 ### Unicode Character Database ``` @@ -7,7 +7,7 @@ UNICODE LICENSE V3 COPYRIGHT AND PERMISSION NOTICE -Copyright © 1991-2024 Unicode, Inc. +Copyright © 1991-2025 Unicode, Inc. NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 43719ff619a..8517e161e3f 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -450,7 +450,7 @@ the JVM. > **Note:** This option will be removed in a future release. - `allow`: This mode allows illegal native access in all modules, - without any warings. + without any warnings. - `warn`: This mode is identical to `allow` except that a warning message is issued for the first illegal native access found in a module. @@ -465,6 +465,39 @@ the JVM. run it with `--illegal-native-access=deny` along with any necessary `--enable-native-access` options. +`--enable-final-field-mutation` *module*\[,*module*...\] +: Mutation of final fields is possible with the reflection API of the Java Platform. + However, it compromises safety and performance in all programs. + This option allows code in the specified modules to mutate final fields by reflection. + Attempts by code in any other module to mutate final fields by reflection are deemed _illegal_. + + *module* can be the name of a module on the module path, or `ALL-UNNAMED` to indicate + code on the class path. + +-`--illegal-final-field-mutation=`*parameter* +: This option specifies a mode for how _illegal_ final field mutation is handled: + + > **Note:** This option will be removed in a future release. + + - `allow`: This mode allows illegal final field mutation in all modules, + without any warnings. + + - `warn`: This mode is identical to `allow` except that a warning message is + issued for the first illegal final field mutation performaed in a module. + This mode is the default for the current JDK but will change in a future + release. + + - `debug`: This mode is identical to `allow` except that a warning message + and stack trace are printed for every illegal final field mutation. + + - `deny`: This mode disables final field mutation. That is, any illegal final + field mutation access causes an `IllegalAccessException`. This mode will + become the default in a future release. + + To verify that your application is ready for a future version of the JDK, + run it with `--illegal-final-field-mutation=deny` along with any necessary + `--enable-final-field-mutation` options. + `--finalization=`*value* : Controls whether the JVM performs finalization of objects. Valid values are "enabled" and "disabled". Finalization is enabled by default, so the @@ -701,7 +734,8 @@ the Java HotSpot Virtual Machine. - A class descriptor is in decorated format (`Lname;`) when it should not be. - A `NULL` parameter is allowed, but its use is questionable. - Calling other JNI functions in the scope of `Get/ReleasePrimitiveArrayCritical` - or `Get/ReleaseStringCritical` + or `Get/ReleaseStringCritical`. + - A JNI call was made to mutate a final field. Expect a performance degradation when this option is used. @@ -2421,8 +2455,7 @@ Java HotSpot VM. `-XX:InitialRAMPercentage=`*percent* : Sets the initial amount of memory that the JVM will use for the Java heap before applying ergonomics heuristics as a percentage of the maximum amount - determined as described in the `-XX:MaxRAM` option. The default value is - 0.2 percent. + determined as described in the `-XX:MaxRAM` option. The following example shows how to set the percentage of the initial amount of memory used for the Java heap: diff --git a/src/java.base/share/native/libjava/VirtualThread.c b/src/java.base/share/native/libjava/VirtualThread.c index 3cacf89e752..5936031f926 100644 --- a/src/java.base/share/native/libjava/VirtualThread.c +++ b/src/java.base/share/native/libjava/VirtualThread.c @@ -32,10 +32,10 @@ #define VIRTUAL_THREAD "Ljava/lang/VirtualThread;" static JNINativeMethod methods[] = { - { "notifyJvmtiStart", "()V", (void *)&JVM_VirtualThreadStart }, - { "notifyJvmtiEnd", "()V", (void *)&JVM_VirtualThreadEnd }, - { "notifyJvmtiMount", "(Z)V", (void *)&JVM_VirtualThreadMount }, - { "notifyJvmtiUnmount", "(Z)V", (void *)&JVM_VirtualThreadUnmount }, + { "endFirstTransition", "()V", (void *)&JVM_VirtualThreadEndFirstTransition }, + { "startFinalTransition", "()V", (void *)&JVM_VirtualThreadStartFinalTransition }, + { "startTransition", "(Z)V", (void *)&JVM_VirtualThreadStartTransition }, + { "endTransition", "(Z)V", (void *)&JVM_VirtualThreadEndTransition }, { "notifyJvmtiDisableSuspend", "(Z)V", (void *)&JVM_VirtualThreadDisableSuspend }, { "postPinnedEvent", "(" STR ")V", (void *)&JVM_VirtualThreadPinnedEvent }, { "takeVirtualThreadListToUnblock", "()" VIRTUAL_THREAD, (void *)&JVM_TakeVirtualThreadListToUnblock}, diff --git a/src/java.base/share/native/libjimage/jimage.cpp b/src/java.base/share/native/libjimage/jimage.cpp index 10e85eb2520..91a86f992e6 100644 --- a/src/java.base/share/native/libjimage/jimage.cpp +++ b/src/java.base/share/native/libjimage/jimage.cpp @@ -110,7 +110,7 @@ JIMAGE_FindResource(JImageFile* image, size_t nameLen = strlen(name); size_t index; - // TBD: assert(moduleNameLen > 0 && "module name must be non-empty"); + assert(moduleNameLen > 0 && "module name must be non-empty"); assert(nameLen > 0 && "name must non-empty"); // If the concatenated string is too long for the buffer, return not found diff --git a/src/java.base/unix/native/libjava/java_props_md.c b/src/java.base/unix/native/libjava/java_props_md.c index 000eb4b953e..1cbc3665ebc 100644 --- a/src/java.base/unix/native/libjava/java_props_md.c +++ b/src/java.base/unix/native/libjava/java_props_md.c @@ -388,8 +388,12 @@ GetJavaProperties(JNIEnv *env) /* supported instruction sets */ { char list[258]; - sysinfo(SI_ISALIST, list, sizeof(list)); - sprops.cpu_isalist = strdup(list); + int ret = sysinfo(SI_ISALIST, list, sizeof(list)); + if (ret == 0) { + sprops.cpu_isalist = strdup(list); + } else { + sprops.cpu_isalist = NULL; + } } #else sprops.cpu_isalist = NULL; @@ -438,7 +442,7 @@ GetJavaProperties(JNIEnv *env) /* Determine the language, country, variant, and encoding from the host, * and store these in the user.language, user.country, user.variant and - * file.encoding system properties. */ + * native.encoding system properties. */ setlocale(LC_ALL, ""); if (ParseLocale(env, LC_CTYPE, &(sprops.format_language), diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java b/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java index d051c833ee7..cd7cc38550c 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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 @@ -610,23 +610,24 @@ class WindowsWatchService boolean criticalError = false; int errorCode = info.error(); int messageSize = info.bytesTransferred(); - if (errorCode == ERROR_NOTIFY_ENUM_DIR) { - // buffer overflow - key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); - } else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) { + if (errorCode != 0 && + errorCode != ERROR_MORE_DATA && + errorCode != ERROR_NOTIFY_ENUM_DIR) { // ReadDirectoryChangesW failed criticalError = true; } else { // ERROR_MORE_DATA is a warning about incomplete // data transfer over TCP/UDP stack. For the case - // [messageSize] is zero in the most of cases. + // [messageSize] is zero in most cases. if (messageSize > 0) { // process non-empty events. processEvents(key, messageSize); - } else if (errorCode == 0) { - // insufficient buffer size - // not described, but can happen. + } else if (errorCode == 0 || + errorCode == ERROR_NOTIFY_ENUM_DIR) { + // errorCode == 0: insufficient buffer size; + // not described, but can happen. + // errorCode == ERROR_NOTIFY_ENUM_DIR: buffer overflow key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); } diff --git a/src/java.base/windows/native/libjava/java_props_md.c b/src/java.base/windows/native/libjava/java_props_md.c index 75587a09d0b..e152dbe9bef 100644 --- a/src/java.base/windows/native/libjava/java_props_md.c +++ b/src/java.base/windows/native/libjava/java_props_md.c @@ -569,7 +569,7 @@ GetJavaProperties(JNIEnv* env) /* * user.language * user.script, user.country, user.variant (if user's environment specifies them) - * file.encoding + * native.encoding */ { /* diff --git a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java index 6b4ae119504..2835143dc4e 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -83,6 +83,11 @@ public enum SourceVersion { * preview, flexible constructor bodies in third preview) * 25: module import declarations, compact source files and * instance main methods, and flexible constructor bodies + * (primitive Types in Patterns, instanceof, and switch in + * third preview) + * 26: no changes (primitive Types in Patterns, instanceof, and + * switch in fourth preview) + * 27: tbd */ /** @@ -476,10 +481,22 @@ public enum SourceVersion { * @since 26 * * @see + * href="https://docs.oracle.com/en/java/javase/26/docs/specs/jls/index.html"> * The Java Language Specification, Java SE 26 Edition */ RELEASE_26, + + /** + * The version introduced by the Java Platform, Standard Edition + * 27. + * + * @since 27 + * + * @see + * The Java Language Specification, Java SE 27 Edition + */ + RELEASE_27, ; // Reduce code churn when appending new constants // Note that when adding constants for newer releases, the @@ -489,7 +506,7 @@ public enum SourceVersion { * {@return the latest source version that can be modeled} */ public static SourceVersion latest() { - return RELEASE_26; + return RELEASE_27; } private static final SourceVersion latestSupported = getLatestSupported(); @@ -504,7 +521,7 @@ public enum SourceVersion { private static SourceVersion getLatestSupported() { int intVersion = Runtime.version().feature(); return (intVersion >= 11) ? - valueOf("RELEASE_" + Math.min(26, intVersion)): + valueOf("RELEASE_" + Math.min(27, intVersion)): RELEASE_10; } diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java index 2b2f80358b0..bfd3b64a757 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java @@ -44,7 +44,7 @@ import javax.annotation.processing.SupportedSourceVersion; * @see AbstractAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractAnnotationValueVisitor14 extends AbstractAnnotationValueVisitor9 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java index 59d1eb28282..31d0545744a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java @@ -50,7 +50,7 @@ import javax.annotation.processing.ProcessingEnvironment; * @see AbstractAnnotationValueVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractAnnotationValueVisitorPreview extends AbstractAnnotationValueVisitor14 { diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java index b624bb9f999..72b796a2cb7 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java @@ -50,7 +50,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractElementVisitor14 extends AbstractElementVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java index 761916a1434..009cf06a8ce 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java @@ -53,7 +53,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractElementVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractElementVisitorPreview extends AbstractElementVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java index 1860cd09ac5..95dfc473da1 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java @@ -47,7 +47,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractTypeVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractTypeVisitor14 extends AbstractTypeVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java index 6b701262a4f..257d7f5aa17 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java @@ -53,7 +53,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractTypeVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractTypeVisitorPreview extends AbstractTypeVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java index cb0e1cfbc9f..58b1d81bcf9 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java @@ -61,7 +61,7 @@ import javax.lang.model.SourceVersion; * @see ElementKindVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class ElementKindVisitor14 extends ElementKindVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java index 0f436e6d1e5..e2183185b80 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java @@ -67,7 +67,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementKindVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class ElementKindVisitorPreview extends ElementKindVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java index 946cf97b092..6f7d8bc5fed 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java @@ -77,7 +77,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementScanner9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class ElementScanner14 extends ElementScanner9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java index a9d8e7c1f3f..27080c7abc5 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java @@ -81,7 +81,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementScanner14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class ElementScannerPreview extends ElementScanner14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java index 9320e18d5dd..a5e32c936e4 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java @@ -52,7 +52,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleAnnotationValueVisitor14 extends SimpleAnnotationValueVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java index 01509c0c4a5..a98161812fe 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java @@ -58,7 +58,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleAnnotationValueVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleAnnotationValueVisitorPreview extends SimpleAnnotationValueVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java index dff1731d3c9..da9797b2750 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java @@ -58,7 +58,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleElementVisitor14 extends SimpleElementVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java index c3896a794c0..158dd24450f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java @@ -61,7 +61,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleElementVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleElementVisitorPreview extends SimpleElementVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java index d06f5d673d3..07b6b2bedbe 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java @@ -56,7 +56,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleTypeVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleTypeVisitor14 extends SimpleTypeVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java index 11e2e8a50d5..ff9a3050e12 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java @@ -62,7 +62,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleTypeVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleTypeVisitorPreview extends SimpleTypeVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java index 295ceb200b8..8c80f4ad79a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java @@ -61,7 +61,7 @@ import static javax.lang.model.SourceVersion.*; * @see TypeKindVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class TypeKindVisitor14 extends TypeKindVisitor9 { /** * Constructor for concrete subclasses to call; uses {@code null} diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java index c0ca3a0450a..62c059c605f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java @@ -66,7 +66,7 @@ import static javax.lang.model.SourceVersion.*; * @see TypeKindVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class TypeKindVisitorPreview extends TypeKindVisitor14 { /** diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m index 90a147aa5a2..14b7ee8c6b5 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m @@ -68,6 +68,11 @@ static jclass sjc_CAccessibility = NULL; sjm_getCurrentAccessiblePopupMenu, fAccessible, fComponent); + CHECK_EXCEPTION(); + if (axComponent == nil) { + return nil; + } + CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:axComponent withEnv:env withView:self->fView isCurrent:YES]; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java index a3098bd9684..63cc1464460 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,6 +61,7 @@ public class BMPImageReaderSpi extends ImageReaderSpi { null, null); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -69,10 +70,12 @@ public class BMPImageReaderSpi extends ImageReaderSpi { registered = true; } + @Override public String getDescription(Locale locale) { return "Standard BMP Image Reader"; } + @Override public boolean canDecodeInput(Object source) throws IOException { if (!(source instanceof ImageInputStream)) { return false; @@ -87,6 +90,7 @@ public class BMPImageReaderSpi extends ImageReaderSpi { return full && (b[0] == 0x42) && (b[1] == 0x4d); } + @Override public ImageReader createReaderInstance(Object extension) throws IIOException { return new BMPImageReader(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java index ae6a7f65a3b..736a1c2194e 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -66,10 +66,12 @@ public class BMPImageWriterSpi extends ImageWriterSpi { null, null); } + @Override public String getDescription(Locale locale) { return "Standard BMP Image Writer"; } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -79,6 +81,7 @@ public class BMPImageWriterSpi extends ImageWriterSpi { registered = true; } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { int dataType= type.getSampleModel().getDataType(); if (dataType < DataBuffer.TYPE_BYTE || dataType > DataBuffer.TYPE_INT) @@ -99,6 +102,7 @@ public class BMPImageWriterSpi extends ImageWriterSpi { return true; } + @Override public ImageWriter createWriterInstance(Object extension) throws IIOException { return new BMPImageWriter(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java index 5e5a4a52d35..48d3bb12f1c 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,10 +94,12 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { null, null); } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -177,6 +179,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { } // Standard tree node methods + @Override protected IIOMetadataNode getStandardChromaNode() { if ((palette != null) && (paletteSize > 0)) { @@ -202,6 +205,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return null; } + @Override protected IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode node = new IIOMetadataNode("Compression"); @@ -212,6 +216,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return node; } + @Override protected IIOMetadataNode getStandardDataNode() { IIOMetadataNode node = new IIOMetadataNode("Data"); @@ -230,6 +235,7 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return node; } + @Override protected IIOMetadataNode getStandardDimensionNode() { if (yPixelsPerMeter > 0.0F && xPixelsPerMeter > 0.0F) { IIOMetadataNode node = new IIOMetadataNode("Dimension"); @@ -251,14 +257,17 @@ public class BMPMetadata extends IIOMetadata implements BMPConstants { return null; } + @Override public void setFromTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("BMPMetadata1")); } + @Override public void mergeTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("BMPMetadata1")); } + @Override public void reset() { throw new IllegalStateException(I18N.getString("BMPMetadata1")); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java index b9ea0ee0fe3..277169a34e0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -194,6 +194,7 @@ public class BMPMetadataFormat extends IIOMetadataFormatImpl { DATATYPE_STRING, true, null); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java index 1f2f444acd7..4d6c4fe49ec 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ public class BMPMetadataFormatResources extends ListResourceBundle { public BMPMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java index 5a064f4f4c5..107ee313b70 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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,6 +79,7 @@ public class BogusColorSpace extends ColorSpace { // specified behavior of the methods vis-a-vis exceptions. // + @Override public float[] toRGB(float[] colorvalue) { if(colorvalue.length < getNumComponents()) { throw new ArrayIndexOutOfBoundsException @@ -93,6 +94,7 @@ public class BogusColorSpace extends ColorSpace { return rgbvalue; } + @Override public float[] fromRGB(float[] rgbvalue) { if(rgbvalue.length < 3) { throw new ArrayIndexOutOfBoundsException @@ -107,6 +109,7 @@ public class BogusColorSpace extends ColorSpace { return colorvalue; } + @Override public float[] toCIEXYZ(float[] colorvalue) { if(colorvalue.length < getNumComponents()) { throw new ArrayIndexOutOfBoundsException @@ -121,6 +124,7 @@ public class BogusColorSpace extends ColorSpace { return xyzvalue; } + @Override public float[] fromCIEXYZ(float[] xyzvalue) { if(xyzvalue.length < 3) { throw new ArrayIndexOutOfBoundsException diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java index 1b63a54d8ff..b11ffeb6287 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/InputStreamAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -39,10 +39,12 @@ public class InputStreamAdapter extends InputStream { this.stream = stream; } + @Override public int read() throws IOException { return stream.read(); } + @Override public int read(byte[] b, int off, int len) throws IOException { return stream.read(b, off, len); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java index a5c283e6c9c..1662d09984d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -58,14 +58,17 @@ public final class SimpleCMYKColorSpace extends ColorSpace { csRGB = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); } + @Override public boolean equals(Object o) { return o instanceof SimpleCMYKColorSpace; } + @Override public int hashCode() { return System.identityHashCode(theInstance); } + @Override public float[] toRGB(float[] colorvalue) { float C = colorvalue[0]; float M = colorvalue[1]; @@ -97,6 +100,7 @@ public final class SimpleCMYKColorSpace extends ColorSpace { return rgbvalue; } + @Override public float[] fromRGB(float[] rgbvalue) { // Convert from sRGB to linear RGB. for (int i = 0; i < 3; i++) { @@ -128,10 +132,12 @@ public final class SimpleCMYKColorSpace extends ColorSpace { return new float[] {C, M, Y, K}; } + @Override public float[] toCIEXYZ(float[] colorvalue) { return csRGB.toCIEXYZ(toRGB(colorvalue)); } + @Override public float[] fromCIEXYZ(float[] xyzvalue) { return fromRGB(csRGB.fromCIEXYZ(xyzvalue)); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java index 1d8c850b4a9..f598aeb06a1 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -74,6 +74,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { protected Hashtable properties = new Hashtable(); /** Returns the X coordinate of the leftmost column of the image. */ + @Override public int getMinX() { return minX; } @@ -89,6 +90,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { } /** Returns the X coordinate of the uppermost row of the image. */ + @Override public int getMinY() { return minY; } @@ -104,11 +106,13 @@ public abstract class SimpleRenderedImage implements RenderedImage { } /** Returns the width of the image. */ + @Override public int getWidth() { return width; } /** Returns the height of the image. */ + @Override public int getHeight() { return height; } @@ -119,11 +123,13 @@ public abstract class SimpleRenderedImage implements RenderedImage { } /** Returns the width of a tile. */ + @Override public int getTileWidth() { return tileWidth; } /** Returns the height of a tile. */ + @Override public int getTileHeight() { return tileHeight; } @@ -131,6 +137,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { /** * Returns the X coordinate of the upper-left pixel of tile (0, 0). */ + @Override public int getTileGridXOffset() { return tileGridXOffset; } @@ -138,6 +145,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { /** * Returns the Y coordinate of the upper-left pixel of tile (0, 0). */ + @Override public int getTileGridYOffset() { return tileGridYOffset; } @@ -147,6 +155,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * getMinTileX() is implemented in terms of getMinX() * and so does not need to be implemented by subclasses. */ + @Override public int getMinTileX() { return XToTileX(getMinX()); } @@ -166,6 +175,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * of getMinTileX() and getMaxTileX() and so does not need to be * implemented by subclasses. */ + @Override public int getNumXTiles() { return getMaxTileX() - getMinTileX() + 1; } @@ -175,6 +185,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * is implemented in terms of getMinY() and so does not need to be * implemented by subclasses. */ + @Override public int getMinTileY() { return YToTileY(getMinY()); } @@ -194,16 +205,19 @@ public abstract class SimpleRenderedImage implements RenderedImage { * of getMinTileY() and getMaxTileY() and so does not need to be * implemented by subclasses. */ + @Override public int getNumYTiles() { return getMaxTileY() - getMinTileY() + 1; } /** Returns the SampleModel of the image. */ + @Override public SampleModel getSampleModel() { return sampleModel; } /** Returns the ColorModel of the image. */ + @Override public ColorModel getColorModel() { return colorModel; } @@ -218,6 +232,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * Object, or the value * java.awt.Image.UndefinedProperty. */ + @Override public Object getProperty(String name) { name = name.toLowerCase(); Object value = properties.get(name); @@ -232,6 +247,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * @return an array of Strings representing valid * property names. */ + @Override public String[] getPropertyNames() { String[] names = null; @@ -379,6 +395,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { return ty*tileHeight + tileGridYOffset; } + @Override public Vector getSources() { return null; } @@ -399,6 +416,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * * @return a Raster containing a copy of this image's data. */ + @Override public Raster getData() { Rectangle rect = new Rectangle(getMinX(), getMinY(), getWidth(), getHeight()); @@ -422,6 +440,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * * @param bounds the region of the RenderedImage to be returned. */ + @Override public Raster getData(Rectangle bounds) { // Get the image bounds. Rectangle imageBounds = getBounds(); @@ -511,6 +530,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { * @return a reference to the supplied WritableRaster, or to a * new WritableRaster if the supplied one was null. */ + @Override public WritableRaster copyData(WritableRaster dest) { // Get the image bounds. Rectangle imageBounds = getBounds(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java index 0cbdefa9127..315270e5916 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SingleTileRenderedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -58,6 +58,7 @@ public class SingleTileRenderedImage extends SimpleRenderedImage { /** * Returns the image's Raster as tile (0, 0). */ + @Override public Raster getTile(int tileX, int tileY) { if (tileX != 0 || tileY != 0) { throw new IllegalArgumentException("tileX != 0 || tileY != 0"); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java index d880c507cba..05fa72f24ae 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -492,6 +492,7 @@ public class StandardMetadataFormat extends IIOMetadataFormatImpl { null); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java index 4a94450d003..20e81dd76fa 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/StandardMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class StandardMetadataFormatResources extends ListResourceBundle { public StandardMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java index 5d6bd401dc6..487f678c1eb 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SubImageInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -43,6 +43,7 @@ public final class SubImageInputStream extends ImageInputStreamImpl { this.startingLength = this.length = length; } + @Override public int read() throws IOException { if (length == 0) { // Local EOF return -1; @@ -52,6 +53,7 @@ public final class SubImageInputStream extends ImageInputStreamImpl { } } + @Override public int read(byte[] b, int off, int len) throws IOException { if (length == 0) { // Local EOF return -1; @@ -63,10 +65,12 @@ public final class SubImageInputStream extends ImageInputStreamImpl { return bytes; } + @Override public long length() { return startingLength; } + @Override public void seek(long pos) throws IOException { stream.seek(pos - startingPos); streamPos = pos; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java index 061f3b1eaf0..bf2768af4e1 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -115,10 +115,12 @@ public class GIFImageMetadata extends GIFMetadata { null, null); } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -252,6 +254,7 @@ public class GIFImageMetadata extends GIFMetadata { return root; } + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -294,6 +297,7 @@ public class GIFImageMetadata extends GIFMetadata { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -315,6 +319,7 @@ public class GIFImageMetadata extends GIFMetadata { return compression_node; } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -332,6 +337,7 @@ public class GIFImageMetadata extends GIFMetadata { return data_node; } + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -365,6 +371,7 @@ public class GIFImageMetadata extends GIFMetadata { // Document not in image + @Override public IIOMetadataNode getStandardTextNode() { if (comments == null) { return null; @@ -391,6 +398,7 @@ public class GIFImageMetadata extends GIFMetadata { return text_node; } + @Override public IIOMetadataNode getStandardTransparencyNode() { if (!transparentColorFlag) { return null; @@ -414,22 +422,26 @@ public class GIFImageMetadata extends GIFMetadata { return transparency_node; } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override public void reset() { throw new IllegalStateException("Metadata is read-only!"); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java index fa55d72bbda..5a6a85a2b57 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -157,6 +157,7 @@ public class GIFImageMetadataFormat extends IIOMetadataFormatImpl { DATATYPE_STRING, true, null); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java index aa9697a8ee9..f9a29cdebba 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class GIFImageMetadataFormatResources extends ListResourceBundle { public GIFImageMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java index 96a5ba436aa..9484484abf8 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -71,10 +71,12 @@ public class GIFImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard GIF image reader"; } + @Override public boolean canDecodeInput(Object input) throws IOException { if (!(input instanceof ImageInputStream)) { return false; @@ -91,6 +93,7 @@ public class GIFImageReaderSpi extends ImageReaderSpi { (b[4] == '7' || b[4] == '9') && b[5] == 'a'; } + @Override public ImageReader createReaderInstance(Object extension) { return new GIFImageReader(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java index 0f1b8aec102..6da6332eb50 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -73,6 +73,7 @@ public class GIFImageWriterSpi extends ImageWriterSpi { ); } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { if (type == null) { throw new IllegalArgumentException("type == null!"); @@ -94,10 +95,12 @@ public class GIFImageWriterSpi extends ImageWriterSpi { } } + @Override public String getDescription(Locale locale) { return "Standard GIF image writer"; } + @Override public ImageWriter createWriterInstance(Object extension) { return new GIFImageWriter(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java index 5fb4dc007b7..dca232352d9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +242,7 @@ abstract class GIFMetadata extends IIOMetadata { extraMetadataFormatClassNames); } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java index 31c1305b58a..b34e96907ee 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,10 +77,12 @@ public class GIFStreamMetadata extends GIFMetadata { } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -149,6 +151,7 @@ public class GIFStreamMetadata extends GIFMetadata { return root; } + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -190,6 +193,7 @@ public class GIFStreamMetadata extends GIFMetadata { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -208,6 +212,7 @@ public class GIFStreamMetadata extends GIFMetadata { return compression_node; } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -230,6 +235,7 @@ public class GIFStreamMetadata extends GIFMetadata { return data_node; } + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -270,6 +276,7 @@ public class GIFStreamMetadata extends GIFMetadata { return dimension_node; } + @Override public IIOMetadataNode getStandardDocumentNode() { IIOMetadataNode document_node = new IIOMetadataNode("Document"); IIOMetadataNode node = null; // scratch node @@ -285,32 +292,38 @@ public class GIFStreamMetadata extends GIFMetadata { return document_node; } + @Override public IIOMetadataNode getStandardTextNode() { // Not in stream return null; } + @Override public IIOMetadataNode getStandardTransparencyNode() { // Not in stream return null; } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { throw new IllegalStateException("Metadata is read-only!"); } + @Override public void reset() { throw new IllegalStateException("Metadata is read-only!"); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java index b598674ccb3..fcdb8b0d13e 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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,6 +92,7 @@ public class GIFStreamMetadataFormat extends IIOMetadataFormatImpl { "0", "255", true, true); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java index 0404b2c88da..65e9f89c557 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFStreamMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class GIFStreamMetadataFormatResources extends ListResourceBundle { public GIFStreamMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java index a3e8a769490..cec4f354ee0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableImageMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,10 +49,12 @@ class GIFWritableImageMetadata extends GIFImageMetadata { null, null); } + @Override public boolean isReadOnly() { return false; } + @Override public void reset() { // Fields from Image Descriptor imageLeftPosition = 0; @@ -96,6 +98,7 @@ class GIFWritableImageMetadata extends GIFImageMetadata { return data.getBytes(ISO_8859_1); } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { Node node = root; if (!node.getNodeName().equals(nativeMetadataFormatName)) { @@ -292,6 +295,7 @@ class GIFWritableImageMetadata extends GIFImageMetadata { } } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { Node node = root; @@ -389,6 +393,7 @@ class GIFWritableImageMetadata extends GIFImageMetadata { } } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java index 8a9a6d865a8..d8863cb4a2d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFWritableStreamMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -55,10 +55,12 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { reset(); } + @Override public boolean isReadOnly() { return false; } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { @@ -77,6 +79,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { } } + @Override public void reset() { version = null; @@ -90,6 +93,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { globalColorTable = null; } + @Override protected void mergeNativeTree(Node root) throws IIOInvalidTreeException { Node node = root; if (!node.getNodeName().equals(nativeMetadataFormatName)) { @@ -164,6 +168,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { } } + @Override protected void mergeStandardTree(Node root) throws IIOInvalidTreeException { Node node = root; @@ -258,6 +263,7 @@ class GIFWritableStreamMetadata extends GIFStreamMetadata { } } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java index 551f4dc4d72..9b1fbd27fc4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -73,6 +73,7 @@ class AdobeMarkerSegment extends MarkerSegment { updateFromNativeNode(node, true); } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("app14Adobe"); node.setAttribute("version", Integer.toString(version)); @@ -108,6 +109,7 @@ class AdobeMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format. */ + @Override void write(ImageOutputStream ios) throws IOException { length = 14; writeTag(ios); @@ -124,6 +126,7 @@ class AdobeMarkerSegment extends MarkerSegment { (new AdobeMarkerSegment(transform)).write(ios); } + @Override void print () { printTag("Adobe APP14"); System.out.print("Version: "); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java index f28e7b35658..f45bded991a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/COMMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -104,6 +104,7 @@ class COMMarkerSegment extends MarkerSegment { * as a user object and a string encoded using ISO-8895-1, as an * attribute. */ + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("com"); node.setAttribute("comment", getComment()); @@ -117,12 +118,14 @@ class COMMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format, directly from the data array. */ + @Override void write(ImageOutputStream ios) throws IOException { length = 2 + data.length; writeTag(ios); ios.write(data); } + @Override void print() { printTag("COM"); System.out.println("<" + getComment() + ">"); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java index c14402522db..634a266354d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,6 +90,7 @@ class DHTMarkerSegment extends MarkerSegment { } } + @Override protected Object clone() { DHTMarkerSegment newGuy = (DHTMarkerSegment) super.clone(); newGuy.tables = new ArrayList<>(tables.size()); @@ -99,6 +100,7 @@ class DHTMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("dht"); for (int i= 0; i(tables.size()); @@ -92,6 +93,7 @@ class DQTMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("dqt"); for (int i= 0; i MAX_THUMB_WIDTH) @@ -949,6 +960,7 @@ class JFIFMarkerSegment extends MarkerSegment { writeThumbnailData(ios, data, writer); } + @Override void print() { System.out.print(name + " width: "); System.out.println(thumbWidth); @@ -978,10 +990,12 @@ class JFIFMarkerSegment extends MarkerSegment { super(thumb); } + @Override int getLength() { return (thumbWidth*thumbHeight*3); } + @Override BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException { @@ -1014,6 +1028,7 @@ class JFIFMarkerSegment extends MarkerSegment { null); } + @Override void write(ImageOutputStream ios, JPEGImageWriter writer) throws IOException { super.write(ios, writer); // width and height @@ -1050,10 +1065,12 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override int getLength() { return (thumbWidth*thumbHeight + PALETTE_SIZE); } + @Override BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException { @@ -1091,6 +1108,7 @@ class JFIFMarkerSegment extends MarkerSegment { null); } + @Override void write(ImageOutputStream ios, JPEGImageWriter writer) throws IOException { super.write(ios, writer); // width and height @@ -1221,6 +1239,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override int getWidth() { int retval = 0; SOFMarkerSegment sof = @@ -1232,6 +1251,7 @@ class JFIFMarkerSegment extends MarkerSegment { return retval; } + @Override int getHeight() { int retval = 0; SOFMarkerSegment sof = @@ -1249,21 +1269,31 @@ class JFIFMarkerSegment extends MarkerSegment { ThumbnailReadListener (JPEGImageReader reader) { this.reader = reader; } + @Override public void sequenceStarted(ImageReader source, int minIndex) {} + @Override public void sequenceComplete(ImageReader source) {} + @Override public void imageStarted(ImageReader source, int imageIndex) {} + @Override public void imageProgress(ImageReader source, float percentageDone) { reader.thumbnailProgress(percentageDone); } + @Override public void imageComplete(ImageReader source) {} + @Override public void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex) {} + @Override public void thumbnailProgress(ImageReader source, float percentageDone) {} + @Override public void thumbnailComplete(ImageReader source) {} + @Override public void readAborted(ImageReader source) {} } + @Override BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException { @@ -1279,6 +1309,7 @@ class JFIFMarkerSegment extends MarkerSegment { return ret; } + @Override protected Object clone() { JFIFThumbJPEG newGuy = (JFIFThumbJPEG) super.clone(); if (thumbMetadata != null) { @@ -1287,6 +1318,7 @@ class JFIFMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("JFIFthumbJPEG"); if (thumbMetadata != null) { @@ -1295,6 +1327,7 @@ class JFIFMarkerSegment extends MarkerSegment { return node; } + @Override int getLength() { if (data == null) { return 0; @@ -1303,6 +1336,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override void write(ImageOutputStream ios, JPEGImageWriter writer) throws IOException { int progInterval = data.length / 20; // approx. every 5% @@ -1322,6 +1356,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override void print () { System.out.println("JFIF thumbnail stored as JPEG"); } @@ -1445,6 +1480,7 @@ class JFIFMarkerSegment extends MarkerSegment { } } + @Override protected Object clone () { ICCMarkerSegment newGuy = (ICCMarkerSegment) super.clone(); if (profile != null) { @@ -1541,6 +1577,7 @@ class JFIFMarkerSegment extends MarkerSegment { return retval; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("app2ICC"); if (profile != null) { @@ -1553,10 +1590,12 @@ class JFIFMarkerSegment extends MarkerSegment { * No-op. Profiles are never written from metadata. * They are written from the ColorSpace of the image. */ + @Override void write(ImageOutputStream ios) throws IOException { // No-op } + @Override void print () { printTag("ICC Profile APP2"); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java index 4c858a47ab1..20b94fb339b 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -337,6 +337,7 @@ public class JPEGImageMetadataFormat extends JPEGMetadataFormat { tabids); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { // All images can have these diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java index e242a355a17..3cbc0054c85 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,6 +122,7 @@ public class JPEGImageMetadataFormatResources public JPEGImageMetadataFormatResources() {} + @Override protected Object[][] getContents() { // return a copy of the combined commonContents and imageContents; // in theory we want a deep clone of the combined arrays, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java index e4b09197aa7..be6fc32a761 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class JPEGImageReaderResources extends ListResourceBundle { public JPEGImageReaderResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java index 450dd89b6f4..ab942ea8de2 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -59,10 +59,12 @@ public class JPEGImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard JPEG Image Reader"; } + @Override public boolean canDecodeInput(Object source) throws IOException { if (!(source instanceof ImageInputStream)) { return false; @@ -80,6 +82,7 @@ public class JPEGImageReaderSpi extends ImageReaderSpi { return false; } + @Override public ImageReader createReaderInstance(Object extension) throws IIOException { return new JPEGImageReader(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java index 3db20b3d39d..3b2a149f6b4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class JPEGImageWriterResources extends ListResourceBundle { public JPEGImageWriterResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java index bd6bcc8d784..d6f5abbbccb 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -63,14 +63,17 @@ public class JPEGImageWriterSpi extends ImageWriterSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard JPEG Image Writer"; } + @Override public boolean isFormatLossless() { return false; } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { SampleModel sampleModel = type.getSampleModel(); ColorModel cm = type.getColorModel(); @@ -95,6 +98,7 @@ public class JPEGImageWriterSpi extends ImageWriterSpi { return true; } + @Override public ImageWriter createWriterInstance(Object extension) throws IIOException { return new JPEGImageWriter(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java index c7ad982b35a..3081fd43404 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java @@ -725,6 +725,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Implement Cloneable, but restrict access + @Override protected Object clone() { JPEGMetadata newGuy = null; try { @@ -755,6 +756,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Tree methods + @Override public Node getAsTree(String formatName) { if (formatName == null) { throw new IllegalArgumentException("null formatName!"); @@ -810,6 +812,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Standard tree node methods + @Override protected IIOMetadataNode getStandardChromaNode() { hasAlpha = false; // Unless we find otherwise @@ -950,6 +953,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return chroma; } + @Override protected IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression = new IIOMetadataNode("Compression"); @@ -980,6 +984,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return compression; } + @Override protected IIOMetadataNode getStandardDimensionNode() { // If we have a JFIF marker segment, we know a little // otherwise all we know is the orientation, which is always normal @@ -1055,6 +1060,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return doc; } + @Override protected IIOMetadataNode getStandardTextNode() { IIOMetadataNode text = null; // Add a text entry for each COM Marker Segment @@ -1073,6 +1079,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return text; } + @Override protected IIOMetadataNode getStandardTransparencyNode() { IIOMetadataNode trans = null; if (hasAlpha == true) { @@ -1086,10 +1093,12 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Editing + @Override public boolean isReadOnly() { return false; } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName == null) { @@ -2160,6 +2169,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { } + @Override public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName == null) { @@ -2404,6 +2414,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { //// End of writer support + @Override public void reset() { if (resetSequence != null) { // Otherwise no need to reset markerSequence = resetSequence; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java index 475cc36359e..53b30f333f0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -123,6 +123,7 @@ abstract class JPEGMetadataFormat extends IIOMetadataFormatImpl { addObjectValue("unknown", byte[].class, 1, MAX_JPEG_DATA_SIZE); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { // Just check if it appears in the format diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java index ea6d2b70138..5e29101e83b 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGStreamMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ public class JPEGStreamMetadataFormatResources public JPEGStreamMetadataFormatResources() {} + @Override protected Object[][] getContents() { // return a copy of commonContents; in theory we want a deep clone // of commonContents, but since it only contains (immutable) Strings, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java index f4ba27b0fcd..74bf598c4d5 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java @@ -110,6 +110,7 @@ class MarkerSegment implements Cloneable { /** * Deep copy of data array. */ + @Override protected Object clone() { MarkerSegment newGuy = null; try { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java index e5b7e861924..fa7acba3325 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -95,6 +95,7 @@ class SOFMarkerSegment extends MarkerSegment { updateFromNativeNode(node, true); } + @Override protected Object clone() { SOFMarkerSegment newGuy = (SOFMarkerSegment) super.clone(); if (componentSpecs != null) { @@ -107,6 +108,7 @@ class SOFMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("sof"); node.setAttribute("process", Integer.toString(tag-JPEG.SOF0)); @@ -154,10 +156,12 @@ class SOFMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format. */ + @Override void write(ImageOutputStream ios) throws IOException { // We don't write SOF segments; the IJG library does. } + @Override void print () { printTag("SOF"); System.out.print("Sample precision: "); @@ -231,6 +235,7 @@ class SOFMarkerSegment extends MarkerSegment { 0, 3, true); } + @Override protected Object clone() { try { return super.clone(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java index f40acdd0375..a34fc43486a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOSMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -89,6 +89,7 @@ class SOSMarkerSegment extends MarkerSegment { updateFromNativeNode(node, true); } + @Override protected Object clone () { SOSMarkerSegment newGuy = (SOSMarkerSegment) super.clone(); if (componentSpecs != null) { @@ -101,6 +102,7 @@ class SOSMarkerSegment extends MarkerSegment { return newGuy; } + @Override IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("sos"); node.setAttribute("numScanComponents", @@ -152,10 +154,12 @@ class SOSMarkerSegment extends MarkerSegment { * Writes the data for this segment to the stream in * valid JPEG format. */ + @Override void write(ImageOutputStream ios) throws IOException { // We don't write SOS segments; the IJG library does. } + @Override void print () { printTag("SOS"); System.out.print("Start spectral selection: "); @@ -208,6 +212,7 @@ class SOSMarkerSegment extends MarkerSegment { 0, 3, true); } + @Override protected Object clone() { try { return super.clone(); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java index 60105e30f8a..bf0576ecb74 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -70,10 +70,12 @@ public class PNGImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard PNG image reader"; } + @Override public boolean canDecodeInput(Object input) throws IOException { if (!(input instanceof ImageInputStream)) { return false; @@ -96,6 +98,7 @@ public class PNGImageReaderSpi extends ImageReaderSpi { b[7] == (byte)10); } + @Override public ImageReader createReaderInstance(Object extension) { return new PNGImageReader(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java index 44080a05a16..3ce07aa4ba5 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -74,6 +74,7 @@ public class PNGImageWriterSpi extends ImageWriterSpi { ); } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { SampleModel sampleModel = type.getSampleModel(); ColorModel colorModel = type.getColorModel(); @@ -116,10 +117,12 @@ public class PNGImageWriterSpi extends ImageWriterSpi { return true; } + @Override public String getDescription(Locale locale) { return "Standard PNG image writer"; } + @Override public ImageWriter createWriterInstance(Object extension) { return new PNGImageWriter(this); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java index 03d00f7ae8e..730294c9f01 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -463,6 +463,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { IHDR_present = true; } + @Override public boolean isReadOnly() { return false; } @@ -480,6 +481,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } // Deep clone + @Override public Object clone() { PNGMetadata metadata; try { @@ -495,6 +497,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return metadata; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -847,6 +850,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return numChannels; } + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -919,6 +923,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -952,6 +957,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return sb.toString(); } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -998,6 +1004,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return data_node; } + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -1027,6 +1034,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return dimension_node; } + @Override public IIOMetadataNode getStandardDocumentNode() { IIOMetadataNode document_node = null; @@ -1067,6 +1075,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return document_node; } + @Override public IIOMetadataNode getStandardTextNode() { int numEntries = tEXt_keyword.size() + iTXt_keyword.size() + zTXt_keyword.size(); @@ -1114,6 +1123,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return text_node; } + @Override public IIOMetadataNode getStandardTransparencyNode() { IIOMetadataNode transparency_node = new IIOMetadataNode("Transparency"); @@ -1285,6 +1295,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { return getAttribute(node, name, null, true); } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { @@ -2267,6 +2278,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable { } // Reset all instance variables to their initial state + @Override public void reset() { IHDR_present = false; PLTE_present = false; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java index b7d96dc3f2b..1518d097903 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -486,6 +486,7 @@ public class PNGMetadataFormat extends IIOMetadataFormatImpl { addObjectValue("UnknownChunk", byte.class, 0, Integer.MAX_VALUE); } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java index d99946bd890..818a2364e23 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class PNGMetadataFormatResources extends ListResourceBundle { public PNGMetadataFormatResources() {} + @Override protected Object[][] getContents() { return new Object[][] { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java index d5adb4e8d35..31806941e35 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +335,7 @@ public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor { return JPEGImageMetadata; } + @Override public final int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java index bc20c57da69..dbddc94516e 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCIELabColorConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +56,7 @@ public class TIFFCIELabColorConverter extends TIFFColorConverter { } } + @Override public void fromRGB(float r, float g, float b, float[] result) { float X = 0.412453f*r + 0.357580f*g + 0.180423f*b; float Y = 0.212671f*r + 0.715160f*g + 0.072169f*b; @@ -100,6 +101,7 @@ public class TIFFCIELabColorConverter extends TIFFColorConverter { result[2] = clamp2(bStar); } + @Override public void toRGB(float x0, float x1, float x2, float[] rgb) { float LStar = x0*100.0f/255.0f; float aStar = (x1 > 128.0f) ? (x1 - 256.0f) : x1; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java index 1ce7d56c1c7..5ade4bacfb4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflateDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ public class TIFFDeflateDecompressor extends TIFFDecompressor { this.predictor = predictor; } + @Override public synchronized void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java index 0fde32a229f..3a5a10245df 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDeflater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -58,6 +58,7 @@ public class TIFFDeflater extends TIFFCompressor { this.deflater = new Deflater(deflateLevel); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java index 3541ce110db..992cba6cbe5 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -39,6 +39,7 @@ public class TIFFExifJPEGCompressor extends TIFFBaseJPEGCompressor { param); } + @Override public void setMetadata(IIOMetadata metadata) { // Set the metadata. super.setMetadata(metadata); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java index 5c126acab53..2af59c682c4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +242,7 @@ abstract class TIFFFaxCompressor extends TIFFCompressor { * * @see #getMetadata() */ + @Override public void setMetadata(IIOMetadata metadata) { super.setMetadata(metadata); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java index a1947dc6b72..64839c033da 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -591,6 +591,7 @@ class TIFFFaxDecompressor extends TIFFDecompressor { * Invokes the superclass method and then sets instance variables on * the basis of the metadata set on this decompressor. */ + @Override public void beginDecoding() { super.beginDecoding(); @@ -627,6 +628,7 @@ class TIFFFaxDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] b, int dstOffset, int pixelBitStride, // will always be 1 int scanlineStride) throws IOException { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java index 6f23fbad4f2..e8878d93315 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -162,6 +162,7 @@ public class TIFFFieldNode extends IIOMetadataNode { // Need to override this method to avoid a stack overflow exception // which will occur if super.appendChild is called from initialize(). + @Override public Node appendChild(Node newChild) { if (newChild == null) { throw new NullPointerException("newChild == null!"); @@ -172,53 +173,63 @@ public class TIFFFieldNode extends IIOMetadataNode { // Override all methods which refer to child nodes. + @Override public boolean hasChildNodes() { initialize(); return super.hasChildNodes(); } + @Override public int getLength() { initialize(); return super.getLength(); } + @Override public Node getFirstChild() { initialize(); return super.getFirstChild(); } + @Override public Node getLastChild() { initialize(); return super.getLastChild(); } + @Override public Node getPreviousSibling() { initialize(); return super.getPreviousSibling(); } + @Override public Node getNextSibling() { initialize(); return super.getNextSibling(); } + @Override public Node insertBefore(Node newChild, Node refChild) { initialize(); return super.insertBefore(newChild, refChild); } + @Override public Node replaceChild(Node newChild, Node oldChild) { initialize(); return super.replaceChild(newChild, oldChild); } + @Override public Node removeChild(Node oldChild) { initialize(); return super.removeChild(oldChild); } + @Override public Node cloneNode(boolean deep) { initialize(); return super.cloneNode(deep); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java index 82ae068d7e4..a3cf39505e6 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -93,6 +93,7 @@ public class TIFFImageMetadata extends IIOMetadata { rootIFD.addTIFFField(field); } + @Override public boolean isReadOnly() { return false; } @@ -149,6 +150,7 @@ public class TIFFImageMetadata extends IIOMetadata { return IFDRoot; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -181,6 +183,7 @@ public class TIFFImageMetadata extends IIOMetadata { "Lab", // ICCLab }; + @Override public IIOMetadataNode getStandardChromaNode() { IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); IIOMetadataNode node = null; // scratch node @@ -278,6 +281,7 @@ public class TIFFImageMetadata extends IIOMetadata { return chroma_node; } + @Override public IIOMetadataNode getStandardCompressionNode() { IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); IIOMetadataNode node = null; // scratch node @@ -336,6 +340,7 @@ public class TIFFImageMetadata extends IIOMetadata { return sb.toString(); } + @Override public IIOMetadataNode getStandardDataNode() { IIOMetadataNode data_node = new IIOMetadataNode("Data"); IIOMetadataNode node = null; // scratch node @@ -476,6 +481,7 @@ public class TIFFImageMetadata extends IIOMetadata { "Rotate90", }; + @Override public IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node @@ -604,6 +610,7 @@ public class TIFFImageMetadata extends IIOMetadata { return dimension_node; } + @Override public IIOMetadataNode getStandardDocumentNode() { IIOMetadataNode document_node = new IIOMetadataNode("Document"); IIOMetadataNode node = null; // scratch node @@ -669,6 +676,7 @@ public class TIFFImageMetadata extends IIOMetadata { return document_node; } + @Override public IIOMetadataNode getStandardTextNode() { IIOMetadataNode text_node = null; IIOMetadataNode node = null; // scratch node @@ -705,6 +713,7 @@ public class TIFFImageMetadata extends IIOMetadata { return text_node; } + @Override public IIOMetadataNode getStandardTransparencyNode() { IIOMetadataNode transparency_node = new IIOMetadataNode("Transparency"); @@ -1579,6 +1588,7 @@ public class TIFFImageMetadata extends IIOMetadata { } } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException{ if (formatName.equals(nativeMetadataFormatName)) { @@ -1597,6 +1607,7 @@ public class TIFFImageMetadata extends IIOMetadata { } } + @Override public void reset() { rootIFD = new TIFFIFD(tagSets); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java index 59c425ec517..edfa3a5be9c 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ public class TIFFImageMetadataFormat extends TIFFMetadataFormat { static { } + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return false; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java index 070836e8854..59e68d0dfe2 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -96,6 +96,7 @@ public class TIFFImageMetadataFormatResources extends ListResourceBundle { public TIFFImageMetadataFormatResources() { } + @Override public Object[][] getContents() { return contents.clone(); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java index 2332e4be2d1..ef21e0b2042 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,10 +56,12 @@ public class TIFFImageReaderSpi extends ImageReaderSpi { ); } + @Override public String getDescription(Locale locale) { return "Standard TIFF image reader"; } + @Override public boolean canDecodeInput(Object input) throws IOException { if (!(input instanceof ImageInputStream)) { return false; @@ -78,10 +80,12 @@ public class TIFFImageReaderSpi extends ImageReaderSpi { b[2] == (byte)0x00 && b[3] == (byte)0x2a)); } + @Override public ImageReader createReaderInstance(Object extension) { return new TIFFImageReader(this); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java index 0b93cbedc0b..a742db6f6bb 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -55,18 +55,22 @@ public class TIFFImageWriterSpi extends ImageWriterSpi { ); } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { return true; } + @Override public String getDescription(Locale locale) { return "Standard TIFF image writer"; } + @Override public ImageWriter createWriterInstance(Object extension) { return new TIFFImageWriter(this); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java index f524f34e32e..e73ccb2b282 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -54,6 +54,7 @@ public class TIFFJPEGCompressor extends TIFFBaseJPEGCompressor { private static class JPEGSPIFilter implements ServiceRegistry.Filter { JPEGSPIFilter() {} + @Override public boolean filter(Object provider) { ImageReaderSpi readerSPI = (ImageReaderSpi)provider; @@ -112,6 +113,7 @@ public class TIFFJPEGCompressor extends TIFFBaseJPEGCompressor { * * @see #getMetadata() */ + @Override public void setMetadata(IIOMetadata metadata) { super.setMetadata(metadata); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java index 3c2ce905958..7353ccea56f 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -54,6 +54,7 @@ public class TIFFJPEGDecompressor extends TIFFDecompressor { public TIFFJPEGDecompressor() {} + @Override public void beginDecoding() { // Initialize the JPEG reader if needed. if(this.JPEGReader == null) { @@ -90,6 +91,7 @@ public class TIFFJPEGDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java index b7bceb89ae4..5052ffedbff 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -36,6 +36,7 @@ public class TIFFLSBCompressor extends TIFFCompressor { super("", BaselineTIFFTagSet.COMPRESSION_NONE, true); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java index d871b6a3e86..6724b779334 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLSBDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ public class TIFFLSBDecompressor extends TIFFDecompressor { public TIFFLSBDecompressor() {} + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java index 4b2b945acb7..6780d65053f 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -41,10 +41,12 @@ public class TIFFLZWCompressor extends TIFFCompressor { this.predictor = predictorValue; } + @Override public void setStream(ImageOutputStream stream) { super.setStream(stream); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java index fc682589ce2..dcf5b2a7f71 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -76,6 +76,7 @@ class TIFFLZWDecompressor extends TIFFDecompressor { flipBits = fillOrder == BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT; } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java index 1091cab9bb2..92d15bfdcb4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -39,6 +39,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { protected String resourceBaseName; protected String rootName; + @Override public String getRootName() { return rootName; } @@ -85,16 +86,19 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info; } + @Override public int getElementMinChildren(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.minChildren; } + @Override public int getElementMaxChildren(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.maxChildren; } + @Override public String getElementDescription(String elementName, Locale locale) { if (!elementInfoMap.containsKey(elementName)) { throw new IllegalArgumentException("No such element: " + @@ -103,64 +107,77 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return getResource(elementName, locale); } + @Override public int getChildPolicy(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.childPolicy; } + @Override public String[] getChildNames(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.childNames; } + @Override public String[] getAttributeNames(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.attributeNames; } + @Override public int getAttributeValueType(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.valueType; } + @Override public int getAttributeDataType(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.dataType; } + @Override public boolean isAttributeRequired(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.isRequired; } + @Override public String getAttributeDefaultValue(String elementName, String attrName) { return null; } + @Override public String[] getAttributeEnumerations(String elementName, String attrName) { throw new IllegalArgumentException("The attribute is not an enumeration."); } + @Override public String getAttributeMinValue(String elementName, String attrName) { throw new IllegalArgumentException("The attribute is not a range."); } + @Override public String getAttributeMaxValue(String elementName, String attrName) { throw new IllegalArgumentException("The attribute is not a range."); } + @Override public int getAttributeListMinLength(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.listMinLength; } + @Override public int getAttributeListMaxLength(String elementName, String attrName) { TIFFAttrInfo info = getAttrInfo(elementName, attrName); return info.listMaxLength; } + @Override public String getAttributeDescription(String elementName, String attrName, Locale locale) { String key = elementName + "/" + attrName; @@ -170,11 +187,13 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return getResource(key, locale); } + @Override public int getObjectValueType(String elementName) { TIFFElementInfo info = getElementInfo(elementName); return info.objectValueType; } + @Override public Class getObjectClass(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -184,6 +203,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectClass; } + @Override public Object getObjectDefaultValue(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -193,6 +213,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectDefaultValue; } + @Override public Object[] getObjectEnumerations(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -202,6 +223,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectEnumerations; } + @Override public Comparable getObjectMinValue(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -211,6 +233,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectMinValue; } + @Override public Comparable getObjectMaxValue(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -220,6 +243,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectMaxValue; } + @Override public int getObjectArrayMinLength(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { @@ -229,6 +253,7 @@ public abstract class TIFFMetadataFormat implements IIOMetadataFormat { return info.objectArrayMinLength; } + @Override public int getObjectArrayMaxLength(String elementName) { TIFFElementInfo info = getElementInfo(elementName); if (info.objectValueType == VALUE_NONE) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java index fc366f791f7..8f6428035d9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ public class TIFFNullCompressor extends TIFFCompressor { super("", BaselineTIFFTagSet.COMPRESSION_NONE, true); } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java index 9b5a746eec1..b73580ef823 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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,6 +56,7 @@ public class TIFFNullDecompressor extends TIFFDecompressor { // change beginDecoding() and decode() to use the active region values // when random access is easy and the entire region values otherwise. // + @Override public void beginDecoding() { // Determine number of bits per pixel. int bitsPerPixel = 0; @@ -89,6 +90,7 @@ public class TIFFNullDecompressor extends TIFFDecompressor { super.beginDecoding(); } + @Override public void decode() throws IOException { super.decode(); @@ -105,6 +107,7 @@ public class TIFFNullDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java index 2935ca5caf8..77594ea8086 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -545,6 +545,7 @@ public class TIFFOldJPEGDecompressor extends TIFFJPEGDecompressor { // The strategy for cases 4-5 is to concatenate a tables stream created // in initialize() with the entropy coded data in each strip or tile. // + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java index 119e4ad4906..b2341f12ed7 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -86,6 +86,7 @@ public class TIFFPackBitsCompressor extends TIFFCompressor { return outOffset; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java index 0a5dfe8308e..61026f57fed 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFPackBitsDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -72,6 +72,7 @@ public class TIFFPackBitsDecompressor extends TIFFDecompressor { return dstIndex - dstOffset; } + @Override public void decodeRaw(byte[] b, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java index 0bf59da81da..1e0270c6ecc 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,7 @@ public class TIFFRLECompressor extends TIFFFaxCompressor { return outIndex; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java index 77e0c9a109c..dadabac3d68 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -130,74 +130,92 @@ public class TIFFRenderedImage implements RenderedImage { return newParam; } + @Override public Vector getSources() { return null; } + @Override public Object getProperty(String name) { return java.awt.Image.UndefinedProperty; } + @Override public String[] getPropertyNames() { return null; } + @Override public ColorModel getColorModel() { return its.getColorModel(); } + @Override public SampleModel getSampleModel() { return its.getSampleModel(); } + @Override public int getWidth() { return width; } + @Override public int getHeight() { return height; } + @Override public int getMinX() { return 0; } + @Override public int getMinY() { return 0; } + @Override public int getNumXTiles() { return (width + tileWidth - 1)/tileWidth; } + @Override public int getNumYTiles() { return (height + tileHeight - 1)/tileHeight; } + @Override public int getMinTileX() { return 0; } + @Override public int getMinTileY() { return 0; } + @Override public int getTileWidth() { return tileWidth; } + @Override public int getTileHeight() { return tileHeight; } + @Override public int getTileGridXOffset() { return 0; } + @Override public int getTileGridYOffset() { return 0; } + @Override public Raster getTile(int tileX, int tileY) { Rectangle tileRect = new Rectangle(tileX*tileWidth, tileY*tileHeight, @@ -206,10 +224,12 @@ public class TIFFRenderedImage implements RenderedImage { return getData(tileRect); } + @Override public Raster getData() { return read(new Rectangle(0, 0, getWidth(), getHeight())); } + @Override public Raster getData(Rectangle rect) { return read(rect); } @@ -236,6 +256,7 @@ public class TIFFRenderedImage implements RenderedImage { } } + @Override public WritableRaster copyData(WritableRaster raster) { if (raster == null) { return read(new Rectangle(0, 0, getWidth(), getHeight())); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java index 96592cc62fb..ac9398fd6e9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -54,6 +54,7 @@ public class TIFFStreamMetadata extends IIOMetadata { null, null); } + @Override public boolean isReadOnly() { return false; } @@ -64,6 +65,7 @@ public class TIFFStreamMetadata extends IIOMetadata { throw new IIOInvalidTreeException(reason, node); } + @Override public Node getAsTree(String formatName) { IIOMetadataNode root = new IIOMetadataNode(nativeMetadataFormatName); @@ -103,6 +105,7 @@ public class TIFFStreamMetadata extends IIOMetadata { } } + @Override public void mergeTree(String formatName, Node root) throws IIOInvalidTreeException { if (formatName.equals(nativeMetadataFormatName)) { @@ -115,6 +118,7 @@ public class TIFFStreamMetadata extends IIOMetadata { } } + @Override public void reset() { this.byteOrder = ByteOrder.BIG_ENDIAN; } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java index bf35133811e..50a3d32e239 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ public class TIFFStreamMetadataFormat extends TIFFMetadataFormat { private static TIFFStreamMetadataFormat theInstance = null; + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return false; diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java index 1e0ea272200..75977c15a41 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFStreamMetadataFormatResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -36,6 +36,7 @@ public class TIFFStreamMetadataFormatResources extends ListResourceBundle { public TIFFStreamMetadataFormatResources() { } + @Override public Object[][] getContents() { return contents.clone(); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java index 55088e34dfe..99d45ce4866 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -52,6 +52,7 @@ public class TIFFT4Compressor extends TIFFFaxCompressor { * * @see #getMetadata() */ + @Override public void setMetadata(IIOMetadata metadata) { super.setMetadata(metadata); @@ -214,6 +215,7 @@ public class TIFFT4Compressor extends TIFFFaxCompressor { return outIndex; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java index 517c23bde54..7e2625d87e2 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -146,6 +146,7 @@ public class TIFFT6Compressor extends TIFFFaxCompressor { return outIndex; } + @Override public int encode(byte[] b, int off, int width, int height, int[] bitsPerSample, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java index a006a3a1e38..b5dae8a9298 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrColorConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -80,6 +80,7 @@ public class TIFFYCbCrColorConverter extends TIFFColorConverter { / CodingRange) + ReferenceBlack; */ + @Override public void fromRGB(float r, float g, float b, float[] result) { // Convert RGB to full-range YCbCr. float Y = (lumaRed*r + lumaGreen*g + lumaBlue*b); @@ -95,6 +96,7 @@ public class TIFFYCbCrColorConverter extends TIFFColorConverter { referenceBlackCr; } + @Override public void toRGB(float x0, float x1, float x2, float[] rgb) { // Convert YCbCr code to full-range YCbCr. float Y = (x0 - referenceBlackY)*CODING_RANGE_Y/ diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java index 0f10904cab4..c0623885d34 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFYCbCrDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -95,6 +95,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { // "Chained" decompressor methods. // + @Override public void setReader(ImageReader reader) { if(decompressor != null) { decompressor.setReader(reader); @@ -102,6 +103,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setReader(reader); } + @Override public void setMetadata(IIOMetadata metadata) { if(decompressor != null) { decompressor.setMetadata(metadata); @@ -109,6 +111,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setMetadata(metadata); } + @Override public void setPhotometricInterpretation(int photometricInterpretation) { if(decompressor != null) { decompressor.setPhotometricInterpretation(photometricInterpretation); @@ -116,6 +119,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setPhotometricInterpretation(photometricInterpretation); } + @Override public void setCompression(int compression) { if(decompressor != null) { decompressor.setCompression(compression); @@ -123,6 +127,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setCompression(compression); } + @Override public void setPlanar(boolean planar) { if(decompressor != null) { decompressor.setPlanar(planar); @@ -130,6 +135,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setPlanar(planar); } + @Override public void setSamplesPerPixel(int samplesPerPixel) { if(decompressor != null) { decompressor.setSamplesPerPixel(samplesPerPixel); @@ -137,6 +143,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSamplesPerPixel(samplesPerPixel); } + @Override public void setBitsPerSample(int[] bitsPerSample) { if(decompressor != null) { decompressor.setBitsPerSample(bitsPerSample); @@ -144,6 +151,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setBitsPerSample(bitsPerSample); } + @Override public void setSampleFormat(int[] sampleFormat) { if(decompressor != null) { decompressor.setSampleFormat(sampleFormat); @@ -151,6 +159,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSampleFormat(sampleFormat); } + @Override public void setExtraSamples(int[] extraSamples) { if(decompressor != null) { decompressor.setExtraSamples(extraSamples); @@ -158,6 +167,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setExtraSamples(extraSamples); } + @Override public void setColorMap(char[] colorMap) { if(decompressor != null) { decompressor.setColorMap(colorMap); @@ -165,6 +175,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setColorMap(colorMap); } + @Override public void setStream(ImageInputStream stream) { if(decompressor != null) { decompressor.setStream(stream); @@ -173,6 +184,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } } + @Override public void setOffset(long offset) { if(decompressor != null) { decompressor.setOffset(offset); @@ -180,6 +192,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setOffset(offset); } + @Override public void setByteCount(int byteCount) throws IOException { if(decompressor != null) { decompressor.setByteCount(byteCount); @@ -187,6 +200,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setByteCount(byteCount); } + @Override public void setSrcMinX(int srcMinX) { if(decompressor != null) { decompressor.setSrcMinX(srcMinX); @@ -194,6 +208,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcMinX(srcMinX); } + @Override public void setSrcMinY(int srcMinY) { if(decompressor != null) { decompressor.setSrcMinY(srcMinY); @@ -201,6 +216,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcMinY(srcMinY); } + @Override public void setSrcWidth(int srcWidth) { if(decompressor != null) { decompressor.setSrcWidth(srcWidth); @@ -208,6 +224,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcWidth(srcWidth); } + @Override public void setSrcHeight(int srcHeight) { if(decompressor != null) { decompressor.setSrcHeight(srcHeight); @@ -215,6 +232,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSrcHeight(srcHeight); } + @Override public void setSourceXOffset(int sourceXOffset) { if(decompressor != null) { decompressor.setSourceXOffset(sourceXOffset); @@ -222,6 +240,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSourceXOffset(sourceXOffset); } + @Override public void setDstXOffset(int dstXOffset) { if(decompressor != null) { decompressor.setDstXOffset(dstXOffset); @@ -229,6 +248,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstXOffset(dstXOffset); } + @Override public void setSourceYOffset(int sourceYOffset) { if(decompressor != null) { decompressor.setSourceYOffset(sourceYOffset); @@ -236,6 +256,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSourceYOffset(sourceYOffset); } + @Override public void setDstYOffset(int dstYOffset) { if(decompressor != null) { decompressor.setDstYOffset(dstYOffset); @@ -260,6 +281,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } */ + @Override public void setSourceBands(int[] sourceBands) { if(decompressor != null) { decompressor.setSourceBands(sourceBands); @@ -267,6 +289,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setSourceBands(sourceBands); } + @Override public void setDestinationBands(int[] destinationBands) { if(decompressor != null) { decompressor.setDestinationBands(destinationBands); @@ -274,6 +297,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDestinationBands(destinationBands); } + @Override public void setImage(BufferedImage image) { if(decompressor != null) { ColorModel cm = image.getColorModel(); @@ -287,6 +311,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setImage(image); } + @Override public void setDstMinX(int dstMinX) { if(decompressor != null) { decompressor.setDstMinX(dstMinX); @@ -294,6 +319,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstMinX(dstMinX); } + @Override public void setDstMinY(int dstMinY) { if(decompressor != null) { decompressor.setDstMinY(dstMinY); @@ -301,6 +327,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstMinY(dstMinY); } + @Override public void setDstWidth(int dstWidth) { if(decompressor != null) { decompressor.setDstWidth(dstWidth); @@ -308,6 +335,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstWidth(dstWidth); } + @Override public void setDstHeight(int dstHeight) { if(decompressor != null) { decompressor.setDstHeight(dstHeight); @@ -315,6 +343,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setDstHeight(dstHeight); } + @Override public void setActiveSrcMinX(int activeSrcMinX) { if(decompressor != null) { decompressor.setActiveSrcMinX(activeSrcMinX); @@ -322,6 +351,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setActiveSrcMinX(activeSrcMinX); } + @Override public void setActiveSrcMinY(int activeSrcMinY) { if(decompressor != null) { decompressor.setActiveSrcMinY(activeSrcMinY); @@ -329,6 +359,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setActiveSrcMinY(activeSrcMinY); } + @Override public void setActiveSrcWidth(int activeSrcWidth) { if(decompressor != null) { decompressor.setActiveSrcWidth(activeSrcWidth); @@ -336,6 +367,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { super.setActiveSrcWidth(activeSrcWidth); } + @Override public void setActiveSrcHeight(int activeSrcHeight) { if(decompressor != null) { decompressor.setActiveSrcHeight(activeSrcHeight); @@ -353,6 +385,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } } + @Override public void beginDecoding() { if(decompressor != null) { decompressor.beginDecoding(); @@ -445,6 +478,7 @@ public class TIFFYCbCrDecompressor extends TIFFDecompressor { } } + @Override public void decodeRaw(byte[] buf, int dstOffset, int bitsPerPixel, diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java index acff45d5b72..9cd967140c9 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -63,6 +63,7 @@ public class WBMPImageReaderSpi extends ImageReaderSpi { null, null); } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -71,10 +72,12 @@ public class WBMPImageReaderSpi extends ImageReaderSpi { registered = true; } + @Override public String getDescription(Locale locale) { return "Standard WBMP Image Reader"; } + @Override public boolean canDecodeInput(Object source) throws IOException { if (!(source instanceof ImageInputStream)) { return false; @@ -149,6 +152,7 @@ public class WBMPImageReaderSpi extends ImageReaderSpi { return result; } + @Override public ImageReader createReaderInstance(Object extension) throws IIOException { return new WBMPImageReader(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java index be2f2d96a38..d6d723c0110 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageWriterSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -63,10 +63,12 @@ public class WBMPImageWriterSpi extends ImageWriterSpi { null, null, null, null); } + @Override public String getDescription(Locale locale) { return "Standard WBMP Image Writer"; } + @Override public void onRegistration(ServiceRegistry registry, Class category) { if (registered) { @@ -76,6 +78,7 @@ public class WBMPImageWriterSpi extends ImageWriterSpi { registered = true; } + @Override public boolean canEncodeImage(ImageTypeSpecifier type) { SampleModel sm = type.getSampleModel(); if (!(sm instanceof MultiPixelPackedSampleModel)) @@ -86,6 +89,7 @@ public class WBMPImageWriterSpi extends ImageWriterSpi { return true; } + @Override public ImageWriter createWriterInstance(Object extension) throws IIOException { return new WBMPImageWriter(this); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java index 3a13bcca94f..f3a63ff7b13 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -50,10 +50,12 @@ public class WBMPMetadata extends IIOMetadata { null, null); } + @Override public boolean isReadOnly() { return true; } + @Override public Node getAsTree(String formatName) { if (formatName.equals(nativeMetadataFormatName)) { return getNativeTree(); @@ -76,14 +78,17 @@ public class WBMPMetadata extends IIOMetadata { return root; } + @Override public void setFromTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("WBMPMetadata1")); } + @Override public void mergeTree(String formatName, Node root) { throw new IllegalStateException(I18N.getString("WBMPMetadata1")); } + @Override public void reset() { throw new IllegalStateException(I18N.getString("WBMPMetadata1")); } @@ -101,6 +106,7 @@ public class WBMPMetadata extends IIOMetadata { } + @Override protected IIOMetadataNode getStandardChromaNode() { IIOMetadataNode node = new IIOMetadataNode("Chroma"); @@ -112,6 +118,7 @@ public class WBMPMetadata extends IIOMetadata { } + @Override protected IIOMetadataNode getStandardDimensionNode() { IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); IIOMetadataNode node = null; // scratch node diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java index 49bce89164a..0aabaa132a3 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/wbmp/WBMPMetadataFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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,6 +56,7 @@ public class WBMPMetadataFormat extends IIOMetadataFormatImpl { + @Override public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { return true; diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java index 81070ff1cb6..3b52fb2b0f0 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageInputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -43,10 +43,12 @@ public class FileImageInputStreamSpi extends ImageInputStreamSpi { super(vendorName, version, inputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageInputStream from a File"; } + @Override public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java index 1ca08005fa1..aa906197d37 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/FileImageOutputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -43,10 +43,12 @@ public class FileImageOutputStreamSpi extends ImageOutputStreamSpi { super(vendorName, version, outputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageOutputStream from a File"; } + @Override public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java index 2591f77a697..266b09c6d9d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/InputStreamImageInputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,18 +46,22 @@ public class InputStreamImageInputStreamSpi extends ImageInputStreamSpi { super(vendorName, version, inputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileCacheImageInputStream or MemoryCacheImageInputStream from an InputStream"; } + @Override public boolean canUseCacheFile() { return true; } + @Override public boolean needsCacheFile() { return false; } + @Override public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java index 391e00feb46..01c7df2145d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/OutputStreamImageOutputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,18 +46,22 @@ public class OutputStreamImageOutputStreamSpi extends ImageOutputStreamSpi { super(vendorName, version, outputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates an OutputStreamImageOutputStream from an OutputStream"; } + @Override public boolean canUseCacheFile() { return true; } + @Override public boolean needsCacheFile() { return false; } + @Override public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java index b5c5112c14e..43498b30dbf 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageInputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -44,10 +44,12 @@ public class RAFImageInputStreamSpi extends ImageInputStreamSpi { super(vendorName, version, inputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageInputStream from a RandomAccessFile"; } + @Override public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java index 373f8754f08..1fe6438b27d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java +++ b/src/java.desktop/share/classes/com/sun/imageio/spi/RAFImageOutputStreamSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -44,10 +44,12 @@ public class RAFImageOutputStreamSpi extends ImageOutputStreamSpi { super(vendorName, version, outputClass); } + @Override public String getDescription(Locale locale) { return "Service provider that instantiates a FileImageOutputStream from a RandomAccessFile"; } + @Override public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java b/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java index 5ea52def657..370606ea08f 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java +++ b/src/java.desktop/share/classes/com/sun/imageio/stream/CloseableDisposerRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -41,6 +41,7 @@ public class CloseableDisposerRecord implements DisposerRecord { this.closeable = closeable; } + @Override public synchronized void dispose() { if (closeable != null) { try { diff --git a/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java b/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java index 229c470335b..7de400ad199 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java +++ b/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -60,6 +60,7 @@ public class StreamCloser { if (streamCloser == null) { final Runnable streamCloserRunnable = new Runnable() { + @Override public void run() { if (toCloseQueue != null) { synchronized (StreamCloser.class) { diff --git a/src/java.desktop/share/classes/java/awt/Robot.java b/src/java.desktop/share/classes/java/awt/Robot.java index e91cc582c4c..d887cad4f77 100644 --- a/src/java.desktop/share/classes/java/awt/Robot.java +++ b/src/java.desktop/share/classes/java/awt/Robot.java @@ -126,6 +126,20 @@ public class Robot { private DirectColorModel screenCapCM = null; + /** + * Default delay in milliseconds for mouse + * {@link #glide(int, int, int, int) glide}, + * {@link #type(int) type}, and + * {@link #click(int) click}. + */ + public static final int DEFAULT_DELAY = 20; + + /** + * Default pixel step-length for mouse + * {@link #glide(int, int, int, int) glide}. + */ + public static final int DEFAULT_STEP_LENGTH = 2; + /** * Constructs a Robot object in the coordinate system of the primary screen. * @@ -773,4 +787,217 @@ public class Robot { String params = "autoDelay = "+getAutoDelay()+", "+"autoWaitForIdle = "+isAutoWaitForIdle(); return getClass().getName() + "[ " + params + " ]"; } + + /** + * A convenience method that simulates clicking a mouse button by calling {@code mousePress}, + * {@code mouseRelease} and {@code waitForIdle}. Invokes {@code waitForIdle} with a default + * delay of {@value #DEFAULT_DELAY} milliseconds after {@code mousePress} and {@code mouseRelease} + * calls. For specifics on valid inputs see {@link java.awt.Robot#mousePress(int)}. + * + * @param buttons The button mask; a combination of one or more mouse button masks. + * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for + * extra mouse button and support for extended mouse buttons is + * {@linkplain Toolkit#areExtraMouseButtonsEnabled() disabled} by Java + * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for + * extra mouse button that does not exist on the mouse and support for extended + * mouse buttons is {@linkplain Toolkit#areExtraMouseButtonsEnabled() enabled} + * by Java + * @throws IllegalThreadStateException if called on the AWT event dispatching thread + * @see #DEFAULT_DELAY + * @see #mousePress(int) + * @see #mouseRelease(int) + * @see InputEvent#getMaskForButton(int) + * @see Toolkit#areExtraMouseButtonsEnabled() + * @see java.awt.event.MouseEvent + * @since 26 + */ + public void click(int buttons) { + try { + mousePress(buttons); + waitForIdle(DEFAULT_DELAY); + } finally { + mouseRelease(buttons); + waitForIdle(DEFAULT_DELAY); + } + } + + /** + * A convenience method that clicks mouse button 1. + * + * @throws IllegalThreadStateException if called on the AWT event dispatching thread + * @see #click(int) + * @since 26 + */ + public void click() { + click(InputEvent.BUTTON1_DOWN_MASK); + } + + /** + * A convenience method that calls {@code waitForIdle} then waits an additional specified + * {@code delayValue} time in milliseconds. + * + * @param delayValue Additional delay length in milliseconds to wait until thread + * sync been completed + * @throws IllegalThreadStateException if called on the AWT event + * dispatching thread + * @throws IllegalArgumentException if {@code delayValue} is not between {@code 0} + * and {@code 60,000} milliseconds inclusive + * @since 26 + */ + public void waitForIdle(int delayValue) { + waitForIdle(); + delay(delayValue); + } + + /** + * A convenience method that moves the mouse in multiple + * steps from its current location to the destination coordinates. + * + * @implSpec Invokes {@link #mouseMove(int, int) mouseMove} with a step-length + * of {@value #DEFAULT_STEP_LENGTH} and a step-delay of {@value #DEFAULT_DELAY}. + * + * @param x Destination point x coordinate + * @param y Destination point y coordinate + * + * @throws IllegalThreadStateException if called on the AWT event dispatching + * thread and {@code isAutoWaitForIdle} would return true + * @see #DEFAULT_STEP_LENGTH + * @see #DEFAULT_DELAY + * @see #glide(int, int, int, int, int, int) + * @since 26 + */ + public void glide(int x, int y) { + Point p = MouseInfo.getPointerInfo().getLocation(); + glide(p.x, p.y, x, y); + } + + /** + * A convenience method that moves the mouse in multiple steps + * from source coordinates to the destination coordinates. + * + * @implSpec Invokes {@link #mouseMove(int, int) mouseMove} with a step-length + * of {@value #DEFAULT_STEP_LENGTH} and a step-delay of {@value #DEFAULT_DELAY}. + * + * @param srcX Source point x coordinate + * @param srcY Source point y coordinate + * @param dstX Destination point x coordinate + * @param dstY Destination point y coordinate + * + * @throws IllegalThreadStateException if called on the AWT event dispatching + * thread and {@code isAutoWaitForIdle} would return true + * @see #DEFAULT_STEP_LENGTH + * @see #DEFAULT_DELAY + * @see #glide(int, int, int, int, int, int) + * @since 26 + */ + public void glide(int srcX, int srcY, int dstX, int dstY) { + glide(srcX, srcY, dstX, dstY, DEFAULT_STEP_LENGTH, DEFAULT_DELAY); + } + + /** + * A convenience method that moves the mouse in multiple + * steps from source point to the destination point with a + * given {@code stepLength} and {@code stepDelay}. + * + * @param srcX Source point x coordinate + * @param srcY Source point y coordinate + * @param destX Destination point x coordinate + * @param destY Destination point y coordinate + * @param stepLength Preferred length of one step in pixels + * @param stepDelay Delay between steps in milliseconds + * + * @throws IllegalArgumentException if {@code stepLength} is not greater than zero + * @throws IllegalArgumentException if {@code stepDelay} is not between {@code 0} + * and {@code 60,000} milliseconds inclusive + * @throws IllegalThreadStateException if called on the AWT event dispatching + * thread and {@code isAutoWaitForIdle} would return true + * @see #mouseMove(int, int) + * @see #delay(int) + * @since 26 + */ + public void glide(int srcX, int srcY, int destX, int destY, int stepLength, int stepDelay) { + if (stepLength <= 0) { + throw new IllegalArgumentException("Step length must be greater than zero"); + } + if (stepDelay <= 0 || stepDelay > 60000) { + throw new IllegalArgumentException("Step delay must be between 0 and 60,000 milliseconds"); + } + + int stepNum; + double tDx, tDy; + double dx, dy, ds; + double x, y; + + dx = (destX - srcX); + dy = (destY - srcY); + ds = Math.sqrt(dx*dx + dy*dy); + + tDx = dx / ds * stepLength; + tDy = dy / ds * stepLength; + + int stepsCount = (int) ds / stepLength; + + // Walk the mouse to the destination one step at a time + mouseMove(srcX, srcY); + + for (x = srcX, y = srcY, stepNum = 0; + stepNum < stepsCount; + stepNum++) { + x += tDx; + y += tDy; + mouseMove((int)x, (int)y); + delay(stepDelay); + } + + // Ensure the mouse moves to the right destination. + // The steps may have led the mouse to a slightly wrong place. + if (x != destX || y != destY) { + mouseMove(destX, destY); + } + } + + /** + * A convenience method that simulates typing a key by calling {@code keyPress} + * and {@code keyRelease}. Invokes {@code waitForIdle} with a delay of {@value #DEFAULT_DELAY} + * milliseconds after {@code keyPress} and {@code keyRelease} calls. + *

    + * Key codes that have more than one physical key associated with them + * (e.g. {@code KeyEvent.VK_SHIFT} could mean either the + * left or right shift key) will map to the left key. + * + * @param keycode Key to type (e.g. {@code KeyEvent.VK_A}) + * @throws IllegalArgumentException if {@code keycode} is not + * a valid key + * @throws IllegalThreadStateException if called on the AWT event dispatching thread + * @see #DEFAULT_DELAY + * @see #keyPress(int) + * @see #keyRelease(int) + * @see java.awt.event.KeyEvent + * @since 26 + */ + public synchronized void type(int keycode) { + keyPress(keycode); + waitForIdle(DEFAULT_DELAY); + keyRelease(keycode); + waitForIdle(DEFAULT_DELAY); + } + + /** + * A convenience method that simulates typing a char by calling {@code keyPress} + * and {@code keyRelease}. Gets the ExtendedKeyCode for the char and calls + * {@code type(int keycode)}. + * + * @param c Character to be typed (e.g. {@code 'a'}) + * @throws IllegalArgumentException if {@code keycode} is not + * a valid key + * @throws IllegalThreadStateException if called on the AWT event dispatching thread + * @see #type(int) + * @see #keyPress(int) + * @see #keyRelease(int) + * @see java.awt.event.KeyEvent + * @since 26 + */ + public synchronized void type(char c) { + type(KeyEvent.getExtendedKeyCodeForChar(c)); + } } diff --git a/src/java.desktop/share/classes/java/awt/font/TextLine.java b/src/java.desktop/share/classes/java/awt/font/TextLine.java index 3464c1626c6..6db1bc72360 100644 --- a/src/java.desktop/share/classes/java/awt/font/TextLine.java +++ b/src/java.desktop/share/classes/java/awt/font/TextLine.java @@ -1020,7 +1020,7 @@ final class TextLine { } TextLineComponent nextComponent = - factory.createExtended(font, cm, decorator, startPos, startPos + lmCount); + factory.createTextLabel(font, cm, decorator, startPos, startPos + lmCount); ++numComponents; if (numComponents > components.length) { diff --git a/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java b/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java index 4c4179699f0..7a3ee8646a7 100644 --- a/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java +++ b/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -186,7 +186,13 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { * {@code getBounds2D(BufferedImage)} * are not necessarily the same as the coordinates of the * {@code BufferedImage} returned by this method. If the - * upper-left corner coordinates of the rectangle are + * application provides a {@code dst} that is always returned. + * If {@code dst} is {@code null} and a destination {code BufferedImage} + * with the transformed dimensions cannot be created, the {@code src} + * dimensions will be substituted. + * + *

    + * If the upper-left corner coordinates of the rectangle are * negative then this part of the rectangle is not drawn. If the * upper-left corner coordinates of the rectangle are positive * then the filtered image is drawn at that position in the @@ -224,7 +230,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { BufferedImage origDst = dst; if (dst == null) { - dst = createCompatibleDestImage(src, null); + dst = createCompatibleDestImageInt(src, null); dstCM = srcCM; origDst = dst; } @@ -272,7 +278,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { } else { needToConvert = true; - dst = createCompatibleDestImage(src, null); + dst = createCompatibleDestImageInt(src, null); } } @@ -320,7 +326,12 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { * {@code getBounds2D(Raster)} * are not necessarily the same as the coordinates of the * {@code WritableRaster} returned by this method. If the - * upper-left corner coordinates of rectangle are negative then + * application provides a {@code dst} that is always returned. + * If {@code dst} is {@code null} and a destination {code Raster} + * with the transformed dimensions cannot be created, the {@code src} + * dimensions will be substituted. + *

    + * If the upper-left corner coordinates of rectangle are negative then * this part of the rectangle is not drawn. If the coordinates * of the rectangle are positive then the filtered image is drawn at * that position in the destination {@code Raster}. @@ -342,7 +353,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { throw new NullPointerException("src image is null"); } if (dst == null) { - dst = createCompatibleDestRaster(src); + dst = createCompatibleDestRasterInt(src); } if (src == dst) { throw new IllegalArgumentException("src image cannot be the "+ @@ -422,7 +433,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { /** * Creates a zeroed destination image with the correct size and number of * bands. A {@code RasterFormatException} may be thrown if the - * transformed width or height is equal to 0. + * transformed width or height is less than or equal to 0, or too large. *

    * If {@code destCM} is null, * an appropriate {@code ColorModel} is used; this @@ -437,9 +448,36 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { */ public BufferedImage createCompatibleDestImage (BufferedImage src, ColorModel destCM) { - BufferedImage image; Rectangle r = getBounds2D(src).getBounds(); + try { + return createCompatibleDestImage(src, destCM, r); + } catch (Exception e) { + if (e instanceof RasterFormatException) { + throw e; + } else { + RasterFormatException re = + new RasterFormatException("Could not create transformed image of size " + r); + re.initCause(e); + throw re; + } + } + } + private BufferedImage createCompatibleDestImageInt(BufferedImage src, + ColorModel destCM) { + + try { + return createCompatibleDestImage(src, destCM); + } catch (Exception e) { + return createCompatibleDestImage(src, destCM, src.getRaster().getBounds()); + } + } + + private BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel destCM, + Rectangle r) { + + BufferedImage image; // If r.x (or r.y) is < 0, then we want to only create an image // that is in the positive range. // If r.x (or r.y) is > 0, then we need to create an image that @@ -482,14 +520,38 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { /** * Creates a zeroed destination {@code Raster} with the correct size * and number of bands. A {@code RasterFormatException} may be thrown - * if the transformed width or height is equal to 0. + * if the transformed width or height is less than or equal to 0, or too large. * * @param src The {@code Raster} to be transformed. * * @return The zeroed destination {@code Raster}. */ public WritableRaster createCompatibleDestRaster (Raster src) { - Rectangle2D r = getBounds2D(src); + Rectangle r = getBounds2D(src).getBounds(); + try { + return createCompatibleDestRaster(src, r); + } catch (Exception e) { + if (e instanceof RasterFormatException) { + throw e; + } else { + RasterFormatException re = + new RasterFormatException("Could not create transformed raster of size " + r); + re.initCause(e); + throw re; + } + } + } + + private WritableRaster createCompatibleDestRasterInt(Raster src) { + try { + return createCompatibleDestRaster(src); + } catch (Exception e) { + Rectangle r = src.getBounds(); + return createCompatibleDestRaster(src, r); + } + } + + private WritableRaster createCompatibleDestRaster (Raster src, Rectangle r) { return src.createCompatibleWritableRaster((int)r.getX(), (int)r.getY(), diff --git a/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java index bad9abc6130..229c8a20d35 100644 --- a/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java @@ -293,6 +293,9 @@ public final class BandedSampleModel extends ComponentSampleModel * @param data The DataBuffer containing the image data. * @return the data for the specified pixel. * @see #setDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code obj} is too small to hold the output. */ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -401,15 +404,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns all samples for the specified pixel in an int array. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples for the specified pixel. - * @see #setPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -434,26 +432,19 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns all samples for the specified rectangle of pixels in - * an int array, one sample per data array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples for the pixels within the specified region. - * @see #setPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative. + * or if {@code iArray} is too small to hold the output. */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -484,16 +475,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns as int the sample in a specified band for the pixel - * located at (x,y). - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return the sample in the specified band for the specified pixel. - * @see #setSample(int, int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public int getSample(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -508,16 +493,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns the sample in a specified band - * for the pixel located at (x,y) as a float. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a float value that represents the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public float getSampleFloat(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -532,16 +511,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns the sample in a specified band - * for a pixel located at (x,y) as a double. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a double value that represents the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public double getSampleDouble(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -556,25 +529,16 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns the samples in a specified band for the specified rectangle - * of pixels in an int array, one sample per data array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param b The band to return - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples in the specified band for the pixels within - * the specified region. - * @see #setSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } @@ -633,6 +597,9 @@ public final class BandedSampleModel extends ComponentSampleModel * object * @param data The DataBuffer containing the image data * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code obj} is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -700,14 +667,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a pixel in the DataBuffer using an int array of samples for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -722,25 +685,19 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets all samples for a rectangle of pixels from an int array containing - * one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative. + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -763,16 +720,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using an int for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as an int - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, int s, DataBuffer data) { @@ -786,16 +737,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using a float for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a float - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, float s , @@ -810,16 +755,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using a double for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a double - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, double s, @@ -834,23 +773,16 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets the samples in the specified band for the specified rectangle - * of pixels from an int array containing one sample per data array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param b The band to set - * @param iArray The input sample array - * @param data The DataBuffer containing the image data - * @see #getSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } diff --git a/src/java.desktop/share/classes/java/awt/image/BufferedImage.java b/src/java.desktop/share/classes/java/awt/image/BufferedImage.java index 09c96a6560f..52bf8a8c4bf 100644 --- a/src/java.desktop/share/classes/java/awt/image/BufferedImage.java +++ b/src/java.desktop/share/classes/java/awt/image/BufferedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -100,10 +100,7 @@ public class BufferedImage extends java.awt.Image * Represents an image with 8-bit RGBA color components packed into * integer pixels. The image has a {@code DirectColorModel} * with alpha. The color data in this image is considered not to be - * premultiplied with alpha. When this type is used as the - * {@code imageType} argument to a {@code BufferedImage} - * constructor, the created image is consistent with images - * created in the JDK1.1 and earlier releases. + * premultiplied with alpha. */ public static final int TYPE_INT_ARGB = 2; diff --git a/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java b/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java index 7a3d67c7e6e..89a72b18dea 100644 --- a/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java @@ -600,7 +600,7 @@ public class ComponentSampleModel extends SampleModel * @return the data of the specified pixel * @see #setDataElements(int, int, Object, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are * not in bounds, or if obj is too small to hold the output. */ @@ -707,20 +707,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns all samples for the specified pixel in an int array, - * one sample per array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x the X coordinate of the pixel location - * @param y the Y coordinate of the pixel location - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples of the specified pixel. - * @see #setPixel(int, int, int[], DataBuffer) - * - * @throws NullPointerException if data is null. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the output. + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -742,26 +732,19 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns all samples for the specified rectangle of pixels in - * an int array, one sample per array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples of the pixels within the specified region. - * @see #setPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the output. */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || y > height || y1 < 0 || y1 > height) + if (x < 0 || (w < 0) || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || (h < 0) || y >= height || y > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -790,16 +773,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns as int the sample in a specified band for the pixel - * located at (x,y). - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x the X coordinate of the pixel location - * @param y the Y coordinate of the pixel location - * @param b the band to return - * @param data the {@code DataBuffer} containing the image data - * @return the sample in a specified band for the specified pixel - * @see #setSample(int, int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public int getSample(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -814,16 +791,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns the sample in a specified band - * for the pixel located at (x,y) as a float. - * An {@code ArrayIndexOutOfBoundsException} might be - * thrown if the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a float value representing the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public float getSampleFloat(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -837,18 +808,11 @@ public class ComponentSampleModel extends SampleModel bandOffsets[b]); return sample; } - /** - * Returns the sample in a specified band - * for a pixel located at (x,y) as a double. - * An {@code ArrayIndexOutOfBoundsException} might be - * thrown if the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a double value representing the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public double getSampleDouble(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -864,25 +828,16 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns the samples in a specified band for the specified rectangle - * of pixels in an int array, one sample per data array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w the width of the pixel rectangle - * @param h the height of the pixel rectangle - * @param b the band to return - * @param iArray if non-{@code null}, returns the samples - * in this array - * @param data the {@code DataBuffer} containing the image data - * @return the samples in the specified band of the specified pixel - * @see #setSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || ( h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } @@ -943,6 +898,9 @@ public class ComponentSampleModel extends SampleModel * @param obj a primitive array containing pixel data * @param data the DataBuffer containing the image data * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -1011,15 +969,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a pixel in the {@code DataBuffer} using an int array of - * samples for input. An {@code ArrayIndexOutOfBoundsException} - * might be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -1034,25 +987,19 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets all samples for a rectangle of pixels from an int array containing - * one sample per array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if the - * coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -1075,16 +1022,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the {@code DataBuffer} using an int for input. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if the - * coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b the band to set - * @param s the input sample as an int - * @param data the DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, int s, DataBuffer data) { @@ -1098,16 +1039,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the {@code DataBuffer} using a float for input. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a float - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, float s , @@ -1123,16 +1058,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the {@code DataBuffer} using a double for input. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a double - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, double s, @@ -1148,23 +1077,16 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets the samples in the specified band for the specified rectangle - * of pixels from an int array containing one sample per data array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if the - * coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param b The band to set - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } diff --git a/src/java.desktop/share/classes/java/awt/image/Kernel.java b/src/java.desktop/share/classes/java/awt/image/Kernel.java index d2b9760aba5..67f62e79b9e 100644 --- a/src/java.desktop/share/classes/java/awt/image/Kernel.java +++ b/src/java.desktop/share/classes/java/awt/image/Kernel.java @@ -25,6 +25,7 @@ package java.awt.image; +import java.util.Objects; /** * The {@code Kernel} class defines a matrix that describes how a @@ -59,7 +60,7 @@ public class Kernel implements Cloneable { * @param width width of the kernel * @param height height of the kernel * @param data kernel data in row major order - * @throws IllegalArgumentException if {@code data} is null + * @throws NullPointerException if {@code data} is null * @throws IllegalArgumentException if {@code width} or {@code height} * is not positive * @throws IllegalArgumentException if product of {@code width} and @@ -69,9 +70,7 @@ public class Kernel implements Cloneable { * {@code height} */ public Kernel(int width, int height, float[] data) { - if (data == null) { - throw new IllegalArgumentException("Data must not be null"); - } + Objects.requireNonNull(data, "Data must not be null"); if ((width <= 0) || (height <= 0)) { throw new IllegalArgumentException("Invalid width or height"); } diff --git a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java index 9254d9fa717..e40da604887 100644 --- a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java @@ -343,7 +343,7 @@ public class MultiPixelPackedSampleModel extends SampleModel * coordinates are not in bounds. * @param x the X coordinate of the specified pixel * @param y the Y coordinate of the specified pixel - * @param b the band to return, which is assumed to be 0 + * @param b the band to return, which must be 0 * @param data the {@code DataBuffer} containing the image * data * @return the specified band containing the sample of the specified @@ -374,7 +374,7 @@ public class MultiPixelPackedSampleModel extends SampleModel * coordinates are not in bounds. * @param x the X coordinate of the specified pixel * @param y the Y coordinate of the specified pixel - * @param b the band to return, which is assumed to be 0 + * @param b the band to set, which must be 0 * @param s the input sample as an {@code int} * @param data the {@code DataBuffer} where image data is stored * @throws ArrayIndexOutOfBoundsException if the coordinates are @@ -448,6 +448,9 @@ public class MultiPixelPackedSampleModel extends SampleModel * not in bounds, or if {@code obj} is not {@code null} or * not large enough to hold the pixel data * @see #setDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {code obj} is too small to hold the output. */ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -527,8 +530,11 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param data the {@code DataBuffer} where image data is stored * @return an array containing the specified pixel. * @throws ArrayIndexOutOfBoundsException if the coordinates - * are not in bounds + * are not in bounds, or if {@code iArray} is too small to hold the output. * @see #setPixel(int, int, int[], DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -588,6 +594,9 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param obj a primitive array containing pixel data * @param data the {@code DataBuffer} containing the image data * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code obj} is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -638,6 +647,9 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param iArray the input pixel in an {@code int} array * @param data the {@code DataBuffer} containing the image data * @see #getPixel(int, int, int[], DataBuffer) + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { diff --git a/src/java.desktop/share/classes/java/awt/image/Raster.java b/src/java.desktop/share/classes/java/awt/image/Raster.java index 9f346cb304a..053e7c1eec5 100644 --- a/src/java.desktop/share/classes/java/awt/image/Raster.java +++ b/src/java.desktop/share/classes/java/awt/image/Raster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -265,9 +265,15 @@ public class Raster { * {@code location.x + w} or * {@code location.y + h} results in integer overflow * @throws IllegalArgumentException if {@code scanlineStride} - * is less than 0 - * @throws IllegalArgumentException if {@code pixelStride} is less than 0 + * is less than or equal to 0 + * @throws IllegalArgumentException if {@code pixelStride} is less than or equal to 0 + * @throws IllegalArgumentException if {@code w * pixelStride} is greater + * than {@code scanlineStride} + * @throws IllegalArgumentException if the data size need to store all + * lines of the image is greater than {@code Integer.MAX_VALUE} * @throws NullPointerException if {@code bandOffsets} is null + * @throws IllegalArgumentException if any element of {@code bandOffsets} is greater + * than {@code pixelStride} or the {@code scanlineStride} */ public static WritableRaster createInterleavedRaster(int dataType, int w, int h, @@ -285,14 +291,25 @@ public class Raster { throw new IllegalArgumentException("Dimensions (width="+w+ " height="+h+") are too large"); } - if (pixelStride < 0) { - throw new IllegalArgumentException("pixelStride is < 0"); + if (pixelStride <= 0) { + throw new IllegalArgumentException("pixelStride is <= 0"); } - if (scanlineStride < 0) { - throw new IllegalArgumentException("scanlineStride is < 0"); + if (scanlineStride <= 0) { + throw new IllegalArgumentException("scanlineStride is <= 0"); } - int size = scanlineStride * (h - 1) + // first (h - 1) scans - pixelStride * w; // last scan + if (bandOffsets == null) { + throw new NullPointerException("bandOffsets is null"); + } + lsz = (long)w * pixelStride; + if (lsz > scanlineStride) { + throw new IllegalArgumentException("w * pixelStride is too large"); + } + lsz = (long)scanlineStride * (long)(h - 1) + // first (h - 1) scans + (long)pixelStride * (long)w; // last scan + if (lsz > Integer.MAX_VALUE) { + throw new IllegalArgumentException("size too large to store image"); + } + int size = (int)lsz; if (location == null) { location = new Point(0, 0); @@ -415,6 +432,10 @@ public class Raster { * is less than 0 * @throws ArrayIndexOutOfBoundsException if {@code bankIndices} * is {@code null} + * @throws IllegalArgumentException if the lengths of {@code bankIndices} + * and {@code bandOffsets} are different. + * @throws IllegalArgumentException if the data size need to store all + * lines of a bank of the image is greater than {@code Integer.MAX_VALUE} * @throws NullPointerException if {@code bandOffsets} is {@code null} */ public static WritableRaster createBandedRaster(int dataType, @@ -423,9 +444,6 @@ public class Raster { int[] bankIndices, int[] bandOffsets, Point location) { - DataBuffer d; - int bands = bandOffsets.length; - if (w <= 0 || h <= 0) { throw new IllegalArgumentException("w and h must be positive"); } @@ -440,7 +458,11 @@ public class Raster { } if (bandOffsets == null) { throw new - ArrayIndexOutOfBoundsException("Band offsets array is null"); + NullPointerException("Band offsets array is null"); + } + if (bandOffsets.length != bankIndices.length) { + throw new IllegalArgumentException( + "bankIndices.length != bandOffsets.length"); } if (location != null) { if ((w + location.getX() > Integer.MAX_VALUE) || @@ -451,6 +473,9 @@ public class Raster { } } + DataBuffer d; + int bands = bandOffsets.length; + // Figure out the #banks and the largest band offset int maxBank = bankIndices[0]; int maxBandOff = bandOffsets[0]; @@ -463,9 +488,15 @@ public class Raster { } } int banks = maxBank + 1; - int size = maxBandOff + - scanlineStride * (h - 1) + // first (h - 1) scans - w; // last scan + + lsz = (long) maxBandOff + + (long)scanlineStride * (h - 1) + // first (h - 1) scans + w; // last scan + if (lsz > Integer.MAX_VALUE) { + throw new IllegalArgumentException("storage size is too large"); + } + + int size = (int)lsz; switch(dataType) { case DataBuffer.TYPE_BYTE: @@ -508,11 +539,14 @@ public class Raster { * @param location the upper-left corner of the {@code Raster} * @return a WritableRaster object with the specified data type, * width, height, and band masks. - * @throws RasterFormatException if {@code w} or {@code h} - * is less than or equal to zero, or computing either + * @throws NullPointerException if {@code bandMasks} is null + * @throws IllegalArgumentException if {@code w} and {@code h} + * are not both greater than 0 + * @throws IllegalArgumentException if the product of {@code w} + * and {@code h} is greater than {@code Integer.MAX_VALUE} + * @throws RasterFormatException if computing either * {@code location.x + w} or - * {@code location.y + h} results in integer - * overflow + * {@code location.y + h} results in integer overflow * @throws IllegalArgumentException if {@code dataType} is not * one of the supported data types, which are * {@code DataBuffer.TYPE_BYTE}, @@ -525,6 +559,24 @@ public class Raster { Point location) { DataBuffer d; + if (w <= 0 || h <= 0) { + throw new IllegalArgumentException("w and h must be positive"); + } + long lsz = (long)w * h; + if (lsz > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Dimensions (width="+w+ + " height="+h+") are too large"); + } + + if (location != null) { + if ((w + location.getX() > Integer.MAX_VALUE) || + (h + location.getY() > Integer.MAX_VALUE)) { + throw new RasterFormatException( + "location.x + w and location.y + h " + + " cannot exceed Integer.MAX_VALUE"); + } + } + switch(dataType) { case DataBuffer.TYPE_BYTE: d = new DataBufferByte(w*h); @@ -573,17 +625,19 @@ public class Raster { * @param location the upper-left corner of the {@code Raster} * @return a WritableRaster object with the specified data type, * width, height, number of bands, and bits per band. - * @throws RasterFormatException if {@code w} or {@code h} - * is less than or equal to zero, or computing either - * {@code location.x + w} or - * {@code location.y + h} results in integer - * overflow + * @throws IllegalArgumentException if {@code bitsPerBand} or + * {@code bands} is not greater than zero * @throws IllegalArgumentException if the product of * {@code bitsPerBand} and {@code bands} is * greater than the number of bits held by * {@code dataType} - * @throws IllegalArgumentException if {@code bitsPerBand} or - * {@code bands} is not greater than zero + * @throws IllegalArgumentException if {@code w} and {@code h} + * are not both greater than 0 + * @throws IllegalArgumentException if the product of {@code w} + * and {@code h} is greater than {@code Integer.MAX_VALUE} + * @throws RasterFormatException if computing either + * {@code location.x + w} or + * {@code location.y + h} results in integer overflow * @throws IllegalArgumentException if {@code dataType} is not * one of the supported data types, which are * {@code DataBuffer.TYPE_BYTE}, @@ -607,18 +661,37 @@ public class Raster { ") must be greater than 0"); } + if (w <= 0 || h <= 0) { + throw new IllegalArgumentException("w and h must be positive"); + } + long lsz = (long)w * h; + if (lsz > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Dimensions (width="+w+ + " height="+h+") are too large"); + } + + if (location != null) { + if ((w + location.getX() > Integer.MAX_VALUE) || + (h + location.getY() > Integer.MAX_VALUE)) { + throw new RasterFormatException( + "location.x + w and location.y + h " + + " cannot exceed Integer.MAX_VALUE"); + } + } + + int shift = (bands-1)*bitsPerBand; + + /* Make sure the total mask size will fit in the data type */ + if (shift+bitsPerBand > DataBuffer.getDataTypeSize(dataType)) { + throw new IllegalArgumentException("bitsPerBand("+ + bitsPerBand+") * bands is "+ + " greater than data type "+ + "size."); + } if (bands != 1) { int[] masks = new int[bands]; int mask = (1 << bitsPerBand) - 1; - int shift = (bands-1)*bitsPerBand; - /* Make sure the total mask size will fit in the data type */ - if (shift+bitsPerBand > DataBuffer.getDataTypeSize(dataType)) { - throw new IllegalArgumentException("bitsPerBand("+ - bitsPerBand+") * bands is "+ - " greater than data type "+ - "size."); - } switch(dataType) { case DataBuffer.TYPE_BYTE: case DataBuffer.TYPE_USHORT: @@ -693,6 +766,7 @@ public class Raster { * {@code DataBuffer.TYPE_USHORT}. * @throws RasterFormatException if {@code dataBuffer} has more * than one bank. + * @throws RasterFormatException if {@code dataBuffer} is too small. * @throws IllegalArgumentException if {@code w} and {@code h} are not * both > 0 * @throws IllegalArgumentException if the product of {@code w} @@ -704,6 +778,8 @@ public class Raster { * is less than 0 * @throws IllegalArgumentException if {@code pixelStride} is less than 0 * @throws NullPointerException if {@code bandOffsets} is null + * @throws IllegalArgumentException if any element of {@code bandOffsets} is greater + * than {@code pixelStride} or the {@code scanlineStride} */ public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer, @@ -779,6 +855,10 @@ public class Raster { * bank indices and band offsets. * @throws NullPointerException if {@code dataBuffer} is null, * or {@code bankIndices} is null, or {@code bandOffsets} is null + * @throws IllegalArgumentException if the lengths of {@code bankIndices} + * and {@code bandOffsets} are different. + * @throws ArrayIndexOutOfBoundsException if any element of {@code bankIndices} + * is greater or equal to the number of bands in {@code dataBuffer} * @throws IllegalArgumentException if {@code dataType} is not * one of the supported data types, which are * {@code DataBuffer.TYPE_BYTE}, @@ -883,11 +963,14 @@ public class Raster { * @return a WritableRaster object with the specified * {@code DataBuffer}, width, height, scanline stride, * and band masks. - * @throws RasterFormatException if {@code w} or {@code h} - * is less than or equal to zero, or computing either + * @throws NullPointerException if {@code bandMasks} is null + * @throws IllegalArgumentException if {@code w} and {@code h} + * are not both greater than 0 + * @throws IllegalArgumentException if the product of {@code w} + * and {@code h} is greater than {@code Integer.MAX_VALUE} + * @throws RasterFormatException if computing either * {@code location.x + w} or - * {@code location.y + h} results in integer - * overflow + * {@code location.y + h} results in integer overflow * @throws IllegalArgumentException if {@code dataBuffer} is not * one of the supported data types, which are * {@code DataBuffer.TYPE_BYTE}, @@ -906,6 +989,25 @@ public class Raster { if (dataBuffer == null) { throw new NullPointerException("DataBuffer cannot be null"); } + + if (w <= 0 || h <= 0) { + throw new IllegalArgumentException("w and h must be positive"); + } + long lsz = (long)w * h; + if (lsz > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Dimensions (width="+w+ + " height="+h+") are too large"); + } + + if (location != null) { + if ((w + location.getX() > Integer.MAX_VALUE) || + (h + location.getY() > Integer.MAX_VALUE)) { + throw new RasterFormatException( + "location.x + w and location.y + h " + + " cannot exceed Integer.MAX_VALUE"); + } + } + if (location == null) { location = new Point(0,0); } @@ -960,11 +1062,13 @@ public class Raster { * @return a WritableRaster object with the specified * {@code DataBuffer}, width, height, and * bits per pixel. - * @throws RasterFormatException if {@code w} or {@code h} - * is less than or equal to zero, or computing either + * @throws IllegalArgumentException if {@code w} and {@code h} + * are not both greater than 0 + * @throws IllegalArgumentException if the product of {@code w} + * and {@code h} is greater than {@code Integer.MAX_VALUE} + * @throws RasterFormatException if computing either * {@code location.x + w} or - * {@code location.y + h} results in integer - * overflow + * {@code location.y + h} results in integer overflow * @throws IllegalArgumentException if {@code dataType} is not * one of the supported data types, which are * {@code DataBuffer.TYPE_BYTE}, @@ -972,6 +1076,8 @@ public class Raster { * or {@code DataBuffer.TYPE_INT} * @throws RasterFormatException if {@code dataBuffer} has more * than one bank. + * @throws RasterFormatException if {@code bitsPixel} is less than 1 or + * not a power of 2 or exceeds the {@code dataBuffer} element size. * @throws NullPointerException if {@code dataBuffer} is null */ public static WritableRaster createPackedRaster(DataBuffer dataBuffer, @@ -982,6 +1088,25 @@ public class Raster { if (dataBuffer == null) { throw new NullPointerException("DataBuffer cannot be null"); } + if (w <= 0 || h <= 0) { + throw new IllegalArgumentException("w and h must be positive"); + } + long lsz = (long)w * h; + + if (lsz > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Dimensions (width="+w+ + " height="+h+") are too large"); + } + + if (location != null) { + if ((w + location.getX() > Integer.MAX_VALUE) || + (h + location.getY() > Integer.MAX_VALUE)) { + throw new RasterFormatException( + "location.x + w and location.y + h " + + " cannot exceed Integer.MAX_VALUE"); + } + } + if (location == null) { location = new Point(0,0); } @@ -1000,6 +1125,12 @@ public class Raster { " must only have 1 bank."); } + if ((bitsPerPixel < 1) || (bitsPerPixel > DataBuffer.getDataTypeSize(dataType))) { + // NB MPPSM checks power of 2 condition + throw new + RasterFormatException("bitsPerPixel must be > 0 and a power of 2 that " + + "does not exceed data buffer element size"); + } MultiPixelPackedSampleModel mppsm = new MultiPixelPackedSampleModel(dataType, w, h, bitsPerPixel); diff --git a/src/java.desktop/share/classes/java/awt/image/SampleModel.java b/src/java.desktop/share/classes/java/awt/image/SampleModel.java index 678925ffd20..0ecd4162c60 100644 --- a/src/java.desktop/share/classes/java/awt/image/SampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/SampleModel.java @@ -231,9 +231,9 @@ public abstract class SampleModel * @return the samples for the specified pixel. * @see #setPixel(int, int, int[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the output. + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { @@ -293,9 +293,9 @@ public abstract class SampleModel * @see java.awt.image.DataBuffer * @see #setDataElements(int, int, Object, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if obj is too small to hold the output. + * not in bounds, or if {@code obj} is too small to hold the output. */ public abstract Object getDataElements(int x, int y, Object obj, DataBuffer data); @@ -347,9 +347,10 @@ public abstract class SampleModel * @see #setDataElements(int, int, int, int, Object, DataBuffer) * @see java.awt.image.DataBuffer * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if obj is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code obj} is too small to hold the output. */ public Object getDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) { @@ -362,8 +363,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -528,7 +529,7 @@ public abstract class SampleModel * @see #getDataElements(int, int, Object, DataBuffer) * @see java.awt.image.DataBuffer * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are * not in bounds, or if obj is too small to hold the input. */ @@ -577,7 +578,7 @@ public abstract class SampleModel * @see #getDataElements(int, int, int, int, Object, DataBuffer) * @see java.awt.image.DataBuffer * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are * not in bounds, or if obj is too small to hold the input. */ @@ -592,8 +593,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -695,9 +696,9 @@ public abstract class SampleModel * @return the samples for the specified pixel. * @see #setPixel(int, int, float[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the output. + * not in bounds, or if {@code fArray} is too small to hold the output. */ public float[] getPixel(int x, int y, float[] fArray, DataBuffer data) { @@ -726,9 +727,9 @@ public abstract class SampleModel * @return the samples for the specified pixel. * @see #setPixel(int, int, double[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if dArray is too small to hold the output. + * not in bounds, or if {@code dArray} is too small to hold the output. */ public double[] getPixel(int x, int y, double[] dArray, DataBuffer data) { @@ -760,9 +761,10 @@ public abstract class SampleModel * @return the samples for the specified region of pixels. * @see #setPixels(int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the output. */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { @@ -772,8 +774,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -808,9 +810,10 @@ public abstract class SampleModel * @return the samples for the specified region of pixels. * @see #setPixels(int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code fArray} is too small to hold the output. */ public float[] getPixels(int x, int y, int w, int h, float[] fArray, DataBuffer data) { @@ -820,8 +823,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -856,9 +859,10 @@ public abstract class SampleModel * @return the samples for the specified region of pixels. * @see #setPixels(int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if dArray is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code dArray} is too small to hold the output. */ public double[] getPixels(int x, int y, int w, int h, double[] dArray, DataBuffer data) { @@ -867,8 +871,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -903,7 +907,7 @@ public abstract class SampleModel * @return the sample in a specified band for the specified pixel. * @see #setSample(int, int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -921,7 +925,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @return the sample in a specified band for the specified pixel. * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -943,7 +947,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @return the sample in a specified band for the specified pixel. * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -971,10 +975,10 @@ public abstract class SampleModel * of pixels. * @see #setSamples(int, int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if iArray is too small to - * hold the output. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { @@ -983,8 +987,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x1 < x || x1 > width || - y < 0 || y1 < y || y1 > height) + if (x < 0 || w < 0 || x1 < x || x1 > width || + y < 0 || h < 0 || y1 < y || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1019,10 +1023,10 @@ public abstract class SampleModel * of pixels. * @see #setSamples(int, int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if fArray is too small to - * hold the output. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public float[] getSamples(int x, int y, int w, int h, int b, float[] fArray, @@ -1032,8 +1036,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x1 < x || x1 > width || - y < 0 || y1 < y || y1 > height) + if (x < 0 || w < 0 || x1 < x || x1 > width || + y < 0 || h < 0 || y1 < y || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates"); } @@ -1068,10 +1072,10 @@ public abstract class SampleModel * of pixels. * @see #setSamples(int, int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if dArray is too small to - * hold the output. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code dArray} is too small to hold the output. */ public double[] getSamples(int x, int y, int w, int h, int b, double[] dArray, @@ -1081,8 +1085,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x1 < x || x1 > width || - y < 0 || y1 < y || y1 > height) + if (x < 0 || w < 0 || x1 < x || x1 > width || + y < 0 || h < 0 || y1 < y || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates"); } @@ -1111,9 +1115,9 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixel(int, int, int[], DataBuffer) * - * @throws NullPointerException if iArray or data is null. + * @throws NullPointerException if {@code iArray} or {code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the input. + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { @@ -1131,9 +1135,9 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixel(int, int, float[], DataBuffer) * - * @throws NullPointerException if fArray or data is null. + * @throws NullPointerException if {@code fArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the input. + * not in bounds, or if {@code fArray} is too small to hold the input. */ public void setPixel(int x, int y, float[] fArray, DataBuffer data) { @@ -1150,9 +1154,9 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixel(int, int, double[], DataBuffer) * - * @throws NullPointerException if dArray or data is null. + * @throws NullPointerException if {@code dArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the input. + * not in bounds, or if {@code dArray} is too small to hold the input. */ public void setPixel(int x, int y, double[] dArray, DataBuffer data) { @@ -1173,9 +1177,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixels(int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if iArray or data is null. + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the input. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { @@ -1183,8 +1188,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1211,9 +1216,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixels(int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if fArray or data is null. + * @throws NullPointerException if {@code fArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the input. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code fArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, float[] fArray, DataBuffer data) { @@ -1221,8 +1227,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width|| - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1249,9 +1255,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixels(int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if dArray or data is null. + * @throws NullPointerException if {@code dArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if dArray is too small to hold the input. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code dArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, double[] dArray, DataBuffer data) { @@ -1259,8 +1266,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1286,7 +1293,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSample(int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -1310,7 +1317,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSample(int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -1338,7 +1345,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSample(int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -1364,10 +1371,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSamples(int, int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if iArray or data is null. + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if iArray is too small to - * hold the input. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { @@ -1375,8 +1382,8 @@ public abstract class SampleModel int Offset=0; int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1402,10 +1409,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSamples(int, int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if fArray or data is null. + * @throws NullPointerException if {@code fArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if fArray is too small to - * hold the input. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code fArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, float[] fArray, DataBuffer data) { @@ -1413,8 +1420,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1440,10 +1447,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSamples(int, int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if dArray or data is null. + * @throws NullPointerException if {@code dArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if dArray is too small to - * hold the input. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code dArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, double[] dArray, DataBuffer data) { @@ -1452,8 +1459,8 @@ public abstract class SampleModel int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } diff --git a/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java index abb669e02c6..a75b5197c44 100644 --- a/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java @@ -357,6 +357,9 @@ public class SinglePixelPackedSampleModel extends SampleModel * @param data The DataBuffer containing the image data. * @return the data for the specified pixel. * @see #setDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the output. */ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -416,15 +419,10 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns all samples in for the specified pixel in an int array. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data. - * @return all samples for the specified pixel. - * @see #setPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int [] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -446,26 +444,20 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns all samples for the specified rectangle of pixels in - * an int array, one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param iArray If non-null, returns the samples in this array. - * @param data The DataBuffer containing the image data. - * @return all samples for the specified region of pixels. - * @see #setPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the output. */ + @Override public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -493,17 +485,10 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns as int the sample in a specified band for the pixel - * located at (x,y). - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param b The band to return. - * @param data The DataBuffer containing the image data. - * @return the sample in a specified band for the specified - * pixel. - * @see #setSample(int, int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public int getSample(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -516,25 +501,16 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns the samples for a specified band for the specified rectangle - * of pixels in an int array, one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param b The band to return. - * @param iArray If non-null, returns the samples in this array. - * @param data The DataBuffer containing the image data. - * @return the samples for the specified band for the specified - * region of pixels. - * @see #setSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } @@ -592,6 +568,9 @@ public class SinglePixelPackedSampleModel extends SampleModel * @param obj A primitive array containing pixel data. * @param data The DataBuffer containing the image data. * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -624,14 +603,10 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Sets a pixel in the DataBuffer using an int array of samples for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param iArray The input samples in an int array. - * @param data The DataBuffer containing the image data. - * @see #getPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, @@ -650,25 +625,19 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Sets all samples for a rectangle of pixels from an int array containing - * one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param iArray The input samples in an int array. - * @param data The DataBuffer containing the image data. - * @see #getPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -692,17 +661,11 @@ public class SinglePixelPackedSampleModel extends SampleModel } } - /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using an int for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param b The band to set. - * @param s The input sample as an int. - * @param data The DataBuffer containing the image data. - * @see #getSample(int, int, int, DataBuffer) + /* + * {inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, int s, DataBuffer data) { @@ -718,23 +681,16 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Sets the samples in the specified band for the specified rectangle - * of pixels from an int array containing one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param b The band to set. - * @param iArray The input samples in an int array. - * @param data The DataBuffer containing the image data. - * @see #getSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } diff --git a/src/java.desktop/share/classes/javax/swing/JList.java b/src/java.desktop/share/classes/javax/swing/JList.java index 301813533d7..8d4497d6f9a 100644 --- a/src/java.desktop/share/classes/javax/swing/JList.java +++ b/src/java.desktop/share/classes/javax/swing/JList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -2497,6 +2497,9 @@ public class JList extends JComponent implements Scrollable, Accessible /** * Returns the distance to scroll to expose the next or previous * row (for vertical scrolling) or column (for horizontal scrolling). + * The scrolling distance returned will be positive, + * unless scrolling for the specified parameters is already + * at its furthest extent, in which case it will return zero. *

    * For horizontal scrolling, if the layout orientation is {@code VERTICAL}, * then the list's font size is returned (or {@code 1} if the font is @@ -2507,8 +2510,9 @@ public class JList extends JComponent implements Scrollable, Accessible * {@code SwingConstants.VERTICAL} * @param direction less or equal to zero to scroll up/back, * greater than zero for down/forward - * @return the "unit" increment for scrolling in the specified direction; - * always positive + * @return the non-negative "unit" increment + * for scrolling in the specified direction + * * @see #getScrollableBlockIncrement * @see Scrollable#getScrollableUnitIncrement * @throws IllegalArgumentException if {@code visibleRect} is {@code null}, or @@ -2529,7 +2533,8 @@ public class JList extends JComponent implements Scrollable, Accessible /* Scroll Down */ if (direction > 0) { Rectangle r = getCellBounds(row, row); - return (r == null) ? 0 : r.height - (visibleRect.y - r.y); + return (r == null) ? 0 : + ((r.height - (visibleRect.y - r.y)) < 0) ? 0 : r.height - (visibleRect.y - r.y); } /* Scroll Up */ else { diff --git a/src/java.desktop/share/classes/javax/swing/JTree.java b/src/java.desktop/share/classes/javax/swing/JTree.java index c081b3cfff8..622c55e2ede 100644 --- a/src/java.desktop/share/classes/javax/swing/JTree.java +++ b/src/java.desktop/share/classes/javax/swing/JTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -777,10 +777,10 @@ public class JTree extends JComponent implements Scrollable, Accessible updateInProgress = true; try { - setUI((TreeUI)UIManager.getUI(this)); - SwingUtilities.updateRendererOrEditorUI(getCellRenderer()); SwingUtilities.updateRendererOrEditorUI(getCellEditor()); + + setUI((TreeUI)UIManager.getUI(this)); } finally { updateInProgress = false; } diff --git a/src/java.desktop/share/classes/javax/swing/border/BevelBorder.java b/src/java.desktop/share/classes/javax/swing/border/BevelBorder.java index 13c9c85ab29..dbcab475072 100644 --- a/src/java.desktop/share/classes/javax/swing/border/BevelBorder.java +++ b/src/java.desktop/share/classes/javax/swing/border/BevelBorder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -95,7 +95,9 @@ public class BevelBorder extends AbstractBorder * @param shadow the color to use for the bevel shadow */ public BevelBorder(int bevelType, Color highlight, Color shadow) { - this(bevelType, highlight.brighter(), highlight, shadow, shadow.brighter()); + this(bevelType, + (highlight != null) ? highlight.brighter() : null, highlight, + shadow, (shadow != null) ? shadow.brighter() : null); } /** diff --git a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalButtonUI.java b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalButtonUI.java index 0bbbab7b45f..c940b4dcead 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalButtonUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -217,6 +217,13 @@ public class MetalButtonUI extends BasicButtonUI { // If there is an icon and no text else if ( isIcon ) { focusRect.setBounds( iconRect ); + } else { + Rectangle emptyRect = new Rectangle(); + emptyRect.x = 5; + emptyRect.y = 5; + emptyRect.width = b.getWidth() - emptyRect.x * 2; + emptyRect.height = b.getHeight() - emptyRect.y * 2; + focusRect.setBounds(emptyRect); } g.setColor(getFocusColor()); diff --git a/src/java.desktop/share/classes/sun/font/Decoration.java b/src/java.desktop/share/classes/sun/font/Decoration.java index 26f5295d8d3..f131914134f 100644 --- a/src/java.desktop/share/classes/sun/font/Decoration.java +++ b/src/java.desktop/share/classes/sun/font/Decoration.java @@ -54,7 +54,8 @@ import static sun.font.EAttribute.*; /** * This class handles underlining, strikethrough, and foreground and * background styles on text. Clients simply acquire instances - * of this class and hand them off to ExtendedTextLabels or GraphicComponents. + * of this class and hand them off to ExtendedTextSourceLabels or + * GraphicComponents. */ public class Decoration { diff --git a/src/java.desktop/share/classes/sun/font/ExtendedTextLabel.java b/src/java.desktop/share/classes/sun/font/ExtendedTextLabel.java deleted file mode 100644 index 2962d8ffc37..00000000000 --- a/src/java.desktop/share/classes/sun/font/ExtendedTextLabel.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/* - * - * (C) Copyright IBM Corp. 1998-2003- All Rights Reserved. - */ - -package sun.font; - -import java.awt.Font; - -import java.awt.font.GlyphJustificationInfo; -import java.awt.font.LineMetrics; - -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -/** - * An extension of TextLabel that maintains information - * about characters. - */ - -public abstract class ExtendedTextLabel extends TextLabel - implements TextLineComponent{ - /** - * Return the number of characters represented by this label. - */ - public abstract int getNumCharacters(); - - /** - * Return the line metrics for all text in this label. - */ - public abstract CoreMetrics getCoreMetrics(); - - /** - * Return the x location of the character at the given logical index. - */ - public abstract float getCharX(int logicalIndex); - - /** - * Return the y location of the character at the given logical index. - */ - public abstract float getCharY(int logicalIndex); - - /** - * Return the advance of the character at the given logical index. - */ - public abstract float getCharAdvance(int logicalIndex); - - /** - * Return the visual bounds of the character at the given logical index. - * This bounds encloses all the pixels of the character when the label is rendered - * at x, y. - */ - public abstract Rectangle2D getCharVisualBounds(int logicalIndex, float x, float y); - - /** - * Return the visual index of the character at the given logical index. - */ - public abstract int logicalToVisual(int logicalIndex); - - /** - * Return the logical index of the character at the given visual index. - */ - public abstract int visualToLogical(int visualIndex); - - /** - * Return the logical index of the character, starting with the character at - * logicalStart, whose accumulated advance exceeds width. If the advances of - * all characters do not exceed width, return getNumCharacters. If width is - * less than zero, return logicalStart - 1. - */ - public abstract int getLineBreakIndex(int logicalStart, float width); - - /** - * Return the accumulated advances of all characters between logicalStart and - * logicalLimit. - */ - public abstract float getAdvanceBetween(int logicalStart, int logicalLimit); - - /** - * Return whether a caret can exist on the leading edge of the - * character at offset. If the character is part of a ligature - * (for example) a caret may not be appropriate at offset. - */ - public abstract boolean caretAtOffsetIsValid(int offset); - - /** - * A convenience overload of getCharVisualBounds that defaults the label origin - * to 0, 0. - */ - public Rectangle2D getCharVisualBounds(int logicalIndex) { - return getCharVisualBounds(logicalIndex, 0, 0); - } - - public abstract TextLineComponent getSubset(int start, int limit, int dir); - - /** - * Return the number of justification records this uses. - */ - public abstract int getNumJustificationInfos(); - - /** - * Return GlyphJustificationInfo objects for the characters between - * charStart and charLimit, starting at offset infoStart. Infos - * will be in visual order. All positions between infoStart and - * getNumJustificationInfos will be set. If a position corresponds - * to a character outside the provided range, it is set to null. - */ - public abstract void getJustificationInfos(GlyphJustificationInfo[] infos, int infoStart, int charStart, int charLimit); - - /** - * Apply deltas to the data in this component, starting at offset - * deltaStart, and return the new component. There are two floats - * for each justification info, for a total of 2 * getNumJustificationInfos. - * The first delta is the left adjustment, the second is the right - * adjustment. - *

    - * If flags[0] is true on entry, rejustification is allowed. If - * the new component requires rejustification (ligatures were - * formed or split), flags[0] will be set on exit. - */ - public abstract TextLineComponent applyJustificationDeltas(float[] deltas, int deltaStart, boolean[] flags); -} diff --git a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java index 784035f4fe2..85c631d6e3e 100644 --- a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java +++ b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java @@ -46,32 +46,35 @@ import java.awt.geom.Rectangle2D; import java.util.Map; -/** - * Default implementation of ExtendedTextLabel. - */ - // {jbr} I made this class package-private to keep the // Decoration.Label API package-private. -/* public */ -class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.Label { +/** + * A label. + * Visual bounds is a rect that encompasses the entire rendered area. + * Logical bounds is a rect that defines how to position this next + * to other objects. + * 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 { - TextSource source; - private Decoration decorator; + private final TextSource source; + private final Decoration decorator; // caches private Font font; private AffineTransform baseTX; private CoreMetrics cm; - Rectangle2D lb; - Rectangle2D ab; - Rectangle2D vb; - Rectangle2D ib; - StandardGlyphVector gv; - float[] charinfo; + private Rectangle2D lb; + private Rectangle2D ab; + private Rectangle2D vb; + private Rectangle2D ib; + private StandardGlyphVector gv; + private float[] charinfo; - float advTracking; + private float advTracking; /** * Create from a TextSource. @@ -116,13 +119,11 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La advTracking = font.getSize() * AttributeValues.getTracking(atts); } - - // TextLabel API - - public Rectangle2D getLogicalBounds() { - return getLogicalBounds(0, 0); - } - + /** + * Return a rectangle that corresponds to the logical bounds of the text + * when this label is rendered at x, y. + * This rectangle is used when positioning text next to other text. + */ public Rectangle2D getLogicalBounds(float x, float y) { if (lb == null) { lb = createLogicalBounds(); @@ -133,13 +134,16 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La (float)lb.getHeight()); } - public float getAdvance() { - if (lb == null) { - lb = createLogicalBounds(); - } - return (float)lb.getWidth(); + public float getAdvance() { + if (lb == null) { + lb = createLogicalBounds(); } + return (float)lb.getWidth(); + } + /** + * Return a rectangle that surrounds the text outline when this label is rendered at x, y. + */ public Rectangle2D getVisualBounds(float x, float y) { if (vb == null) { vb = decorator.getVisualBounds(this); @@ -150,6 +154,12 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La (float)vb.getHeight()); } + /** + * Return a rectangle that corresponds to the alignment bounds of the text + * when this label is rendered at x, y. This rectangle is used when positioning text next + * to a margin. It differs from the logical bounds in that it does not include leading or + * trailing whitespace. + */ public Rectangle2D getAlignBounds(float x, float y) { if (ab == null) { ab = createAlignBounds(); @@ -161,6 +171,10 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La } + /** + * Return a rectangle that corresponds to the logical bounds of the text, adjusted + * to angle the leading and trailing edges by the italic angle. + */ public Rectangle2D getItalicBounds(float x, float y) { if (ib == null) { ib = createItalicBounds(); @@ -189,6 +203,9 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La return getGV().getOutline(x, y); } + /** + * Return an outline of the characters in the label when rendered at x, y. + */ public Shape getOutline(float x, float y) { return decorator.getOutline(this, x, y); } @@ -197,10 +214,63 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La g.drawGlyphVector(getGV(), x, y); } + /** + * Render the label at x, y in the graphics. + */ public void draw(Graphics2D g, float x, float y) { decorator.drawTextAndDecorations(this, g, x, y); } + /** + * A convenience method that returns the visual bounds when rendered at 0, 0. + */ + public Rectangle2D getVisualBounds() { + return getVisualBounds(0f, 0f); + } + + /** + * A convenience method that returns the logical bounds when rendered at 0, 0. + */ + public Rectangle2D getLogicalBounds() { + return getLogicalBounds(0f, 0f); + } + + /** + * A convenience method that returns the align bounds when rendered at 0, 0. + */ + public Rectangle2D getAlignBounds() { + return getAlignBounds(0f, 0f); + } + + /** + * A convenience method that returns the italic bounds when rendered at 0, 0. + */ + public Rectangle2D getItalicBounds() { + return getItalicBounds(0f, 0f); + } + + /** + * A convenience method that returns the outline when rendered at 0, 0. + */ + public Shape getOutline() { + return getOutline(0f, 0f); + } + + /** + * A convenience method that renders the label at 0, 0. + */ + public void draw(Graphics2D g) { + draw(g, 0f, 0f); + } + + /** + * A convenience overload of getCharVisualBounds that defaults the label origin + * to 0, 0. + */ + public Rectangle2D getCharVisualBounds(int logicalIndex) { + return getCharVisualBounds(logicalIndex, 0, 0); + } + /** * The logical bounds extends from the origin of the glyphvector to the * position at which a following glyphvector's origin should be placed. @@ -336,8 +406,6 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La return gv; } - // ExtendedTextLabel API - private static final int posx = 0, posy = 1, advx = 2, @@ -348,14 +416,23 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La vish = 7; private static final int numvals = 8; + /** + * Return the number of characters represented by this label. + */ public int getNumCharacters() { return source.getLength(); } + /** + * Return the line metrics for all text in this label. + */ public CoreMetrics getCoreMetrics() { return cm; } + /** + * Return the x location of the character at the given logical index. + */ public float getCharX(int index) { validate(index); float[] charinfo = getCharinfo(); @@ -367,6 +444,9 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La } } + /** + * Return the y location of the character at the given logical index. + */ public float getCharY(int index) { validate(index); float[] charinfo = getCharinfo(); @@ -378,6 +458,9 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La } } + /** + * Return the advance of the character at the given logical index. + */ public float getCharAdvance(int index) { validate(index); float[] charinfo = getCharinfo(); @@ -403,6 +486,11 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La charinfo[index + vish]); } + /** + * Return the visual bounds of the character at the given logical index. + * This bounds encloses all the pixels of the character when the label is rendered + * at x, y. + */ public Rectangle2D getCharVisualBounds(int index, float x, float y) { Rectangle2D bounds = decorator.getCharVisualBounds(this, index); @@ -470,16 +558,28 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La } */ + /** + * Return the visual index of the character at the given logical index. + */ public int logicalToVisual(int logicalIndex) { validate(logicalIndex); return l2v(logicalIndex); } + /** + * Return the logical index of the character at the given visual index. + */ public int visualToLogical(int visualIndex) { validate(visualIndex); return v2l(visualIndex); } + /** + * Return the logical index of the character, starting with the character at + * logicalStart, whose accumulated advance exceeds width. If the advances of + * all characters do not exceed width, return getNumCharacters. If width is + * less than zero, return logicalStart - 1. + */ public int getLineBreakIndex(int start, float width) { final float epsilon = 0.005f; @@ -504,6 +604,10 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La return start; } + /** + * Return the accumulated advances of all characters between logicalStart and + * logicalLimit. + */ public float getAdvanceBetween(int start, int limit) { float a = 0f; @@ -523,6 +627,11 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La return a; } + /** + * Return whether a caret can exist on the leading edge of the + * character at offset. If the character is part of a ligature + * (for example) a caret may not be appropriate at offset. + */ public boolean caretAtOffsetIsValid(int offset) { // REMIND: improve this implementation @@ -912,15 +1021,20 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La return sb.toString(); } - //public static ExtendedTextLabel create(TextSource source) { - // return new ExtendedTextSourceLabel(source); - //} - + /** + * Return the number of justification records this uses. + */ public int getNumJustificationInfos() { return getGV().getNumGlyphs(); } - + /** + * Return GlyphJustificationInfo objects for the characters between + * charStart and charLimit, starting at offset infoStart. Infos + * will be in visual order. All positions between infoStart and + * getNumJustificationInfos will be set. If a position corresponds + * to a character outside the provided range, it is set to null. + */ public void getJustificationInfos(GlyphJustificationInfo[] infos, int infoStart, int charStart, int charLimit) { // This simple implementation only uses spaces for justification. // Since regular characters aren't justified, we don't need to deal with @@ -992,6 +1106,17 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La } } + /** + * Apply deltas to the data in this component, starting at offset + * deltaStart, and return the new component. There are two floats + * for each justification info, for a total of 2 * getNumJustificationInfos. + * The first delta is the left adjustment, the second is the right + * adjustment. + *

    + * If flags[0] is true on entry, rejustification is allowed. If + * the new component requires rejustification (ligatures were + * formed or split), flags[0] will be set on exit. + */ public TextLineComponent applyJustificationDeltas(float[] deltas, int deltaStart, boolean[] flags) { // when we justify, we need to adjust the charinfo since spaces diff --git a/src/java.desktop/share/classes/sun/font/TextLabel.java b/src/java.desktop/share/classes/sun/font/TextLabel.java deleted file mode 100644 index 738ff0c294d..00000000000 --- a/src/java.desktop/share/classes/sun/font/TextLabel.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/* - * - * (C) Copyright IBM Corp. 1998-2003 All Rights Reserved - */ - -package sun.font; - -import java.awt.Graphics2D; -import java.awt.Shape; - -import java.awt.geom.Rectangle2D; - -/** - * A label. - * Visual bounds is a rect that encompasses the entire rendered area. - * Logical bounds is a rect that defines how to position this next - * to other objects. - * Align bounds is a rect that defines how to align this to margins. - * it generally allows some overhang that logical bounds would prevent. - */ -public abstract class TextLabel { - - /** - * Return a rectangle that surrounds the text outline when this label is rendered at x, y. - */ - public abstract Rectangle2D getVisualBounds(float x, float y); - - /** - * Return a rectangle that corresponds to the logical bounds of the text - * when this label is rendered at x, y. - * This rectangle is used when positioning text next to other text. - */ - public abstract Rectangle2D getLogicalBounds(float x, float y); - - /** - * Return a rectangle that corresponds to the alignment bounds of the text - * when this label is rendered at x, y. This rectangle is used when positioning text next - * to a margin. It differs from the logical bounds in that it does not include leading or - * trailing whitespace. - */ - public abstract Rectangle2D getAlignBounds(float x, float y); - - /** - * Return a rectangle that corresponds to the logical bounds of the text, adjusted - * to angle the leading and trailing edges by the italic angle. - */ - public abstract Rectangle2D getItalicBounds(float x, float y); - - /** - * Return an outline of the characters in the label when rendered at x, y. - */ - public abstract Shape getOutline(float x, float y); - - /** - * Render the label at x, y in the graphics. - */ - public abstract void draw(Graphics2D g, float x, float y); - - /** - * A convenience method that returns the visual bounds when rendered at 0, 0. - */ - public Rectangle2D getVisualBounds() { - return getVisualBounds(0f, 0f); - } - - /** - * A convenience method that returns the logical bounds when rendered at 0, 0. - */ - public Rectangle2D getLogicalBounds() { - return getLogicalBounds(0f, 0f); - } - - /** - * A convenience method that returns the align bounds when rendered at 0, 0. - */ - public Rectangle2D getAlignBounds() { - return getAlignBounds(0f, 0f); - } - - /** - * A convenience method that returns the italic bounds when rendered at 0, 0. - */ - public Rectangle2D getItalicBounds() { - return getItalicBounds(0f, 0f); - } - - /** - * A convenience method that returns the outline when rendered at 0, 0. - */ - public Shape getOutline() { - return getOutline(0f, 0f); - } - - /** - * A convenience method that renders the label at 0, 0. - */ - public void draw(Graphics2D g) { - draw(g, 0f, 0f); - } -} diff --git a/src/java.desktop/share/classes/sun/font/TextLabelFactory.java b/src/java.desktop/share/classes/sun/font/TextLabelFactory.java index 7a41bd2e7f5..996986617de 100644 --- a/src/java.desktop/share/classes/sun/font/TextLabelFactory.java +++ b/src/java.desktop/share/classes/sun/font/TextLabelFactory.java @@ -42,8 +42,7 @@ import java.text.Bidi; * @see Font * @see FontRenderContext * @see java.awt.font.GlyphVector - * @see TextLabel - * @see ExtendedTextLabel + * @see ExtendedTextSourceLabel * @see Bidi * @see java.awt.font.TextLayout */ @@ -100,7 +99,7 @@ public final class TextLabelFactory { } /** - * Create an extended glyph array for the text between start and limit. + * Create a glyph array for the text between start and limit. * * @param font the font to use to generate glyphs and character positions. * @param start the start of the subrange for which to create the glyph array @@ -113,11 +112,11 @@ public final class TextLabelFactory { * at start. Clients should ensure that all text between start and limit * has the same bidi level for the current line. */ - public ExtendedTextLabel createExtended(Font font, - CoreMetrics lm, - Decoration decorator, - int start, - int limit) { + public ExtendedTextSourceLabel createTextLabel(Font font, + CoreMetrics lm, + Decoration decorator, + int start, + int limit) { if (start > limit || start < lineStart || limit > lineLimit) { throw new IllegalArgumentException("bad start: " + start + " or limit: " + limit); @@ -132,29 +131,4 @@ public final class TextLabelFactory { TextSource source = new StandardTextSource(text, start, limit - start, lineStart, lineLimit - lineStart, level, layoutFlags, font, frc, lm); return new ExtendedTextSourceLabel(source, decorator); } - - /** - * Create a simple glyph array for the text between start and limit. - * - * @param font the font to use to generate glyphs and character positions. - * @param start the start of the subrange for which to create the glyph array - * @param limit the limit of the subrange for which to create glyph array - */ - public TextLabel createSimple(Font font, - CoreMetrics lm, - int start, - int limit) { - - if (start > limit || start < lineStart || limit > lineLimit) { - throw new IllegalArgumentException("bad start: " + start + " or limit: " + limit); - } - - int level = lineBidi == null ? 0 : lineBidi.getLevelAt(start - lineStart); - int linedir = (lineBidi == null || lineBidi.baseIsLeftToRight()) ? 0 : 1; - int layoutFlags = flags & ~0x9; // remove bidi, line direction flags - if ((level & 0x1) != 0) layoutFlags |= 1; // rtl - if ((linedir & 0x1) != 0) layoutFlags |= 8; // line rtl - TextSource source = new StandardTextSource(text, start, limit - start, lineStart, lineLimit - lineStart, level, layoutFlags, font, frc, lm); - return new TextSourceLabel(source); - } } diff --git a/src/java.desktop/share/classes/sun/font/TextSourceLabel.java b/src/java.desktop/share/classes/sun/font/TextSourceLabel.java deleted file mode 100644 index 8514be6ac7a..00000000000 --- a/src/java.desktop/share/classes/sun/font/TextSourceLabel.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/* - * - * (C) Copyright IBM Corp. 1998, 1999 - All Rights Reserved - */ - -package sun.font; - -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.font.FontRenderContext; -import java.awt.font.GlyphVector; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; - -/** - * Implementation of TextLabel based on String. - */ - -public class TextSourceLabel extends TextLabel { - TextSource source; - - // caches - Rectangle2D lb; - Rectangle2D ab; - Rectangle2D vb; - Rectangle2D ib; - GlyphVector gv; - - public TextSourceLabel(TextSource source) { - this(source, null, null, null); - } - - public TextSourceLabel(TextSource source, Rectangle2D lb, Rectangle2D ab, GlyphVector gv) { - this.source = source; - - this.lb = lb; - this.ab = ab; - this.gv = gv; - } - - public TextSource getSource() { - return source; - } - - public final Rectangle2D getLogicalBounds(float x, float y) { - if (lb == null) { - lb = createLogicalBounds(); - } - return new Rectangle2D.Float((float)(lb.getX() + x), - (float)(lb.getY() + y), - (float)lb.getWidth(), - (float)lb.getHeight()); - } - - public final Rectangle2D getVisualBounds(float x, float y) { - if (vb == null) { - vb = createVisualBounds(); - - } - return new Rectangle2D.Float((float)(vb.getX() + x), - (float)(vb.getY() + y), - (float)vb.getWidth(), - (float)vb.getHeight()); - } - - public final Rectangle2D getAlignBounds(float x, float y) { - if (ab == null) { - ab = createAlignBounds(); - } - return new Rectangle2D.Float((float)(ab.getX() + x), - (float)(ab.getY() + y), - (float)ab.getWidth(), - (float)ab.getHeight()); - } - - public Rectangle2D getItalicBounds(float x, float y) { - if (ib == null) { - ib = createItalicBounds(); - } - return new Rectangle2D.Float((float)(ib.getX() + x), - (float)(ib.getY() + y), - (float)ib.getWidth(), - (float)ib.getHeight()); - - } - - public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) { - return getGV().getPixelBounds(frc, x, y); // no cache - } - - public AffineTransform getBaselineTransform() { - Font font = source.getFont(); - if (font.hasLayoutAttributes()) { - return AttributeValues.getBaselineTransform(font.getAttributes()); - } - return null; - } - - public Shape getOutline(float x, float y) { - return getGV().getOutline(x, y); - } - - public void draw(Graphics2D g, float x, float y) { - g.drawGlyphVector(getGV(), x, y); - } - - protected Rectangle2D createLogicalBounds() { - return getGV().getLogicalBounds(); - } - - protected Rectangle2D createVisualBounds() { - return getGV().getVisualBounds(); - } - - protected Rectangle2D createItalicBounds() { - // !!! fix - return getGV().getLogicalBounds(); - } - - protected Rectangle2D createAlignBounds() { - return createLogicalBounds(); - } - - private GlyphVector getGV() { - if (gv == null) { - gv = createGV(); - } - - return gv; - } - - protected GlyphVector createGV() { - Font font = source.getFont(); - FontRenderContext frc = source.getFRC(); - int flags = source.getLayoutFlags(); - char[] context = source.getChars(); - int start = source.getStart(); - int length = source.getLength(); - - GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines - StandardGlyphVector gv = gl.layout(font, frc, context, start, length, - flags, null); // ??? use textsource - GlyphLayout.done(gl); - - return gv; - } -} diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java index 63a1359323f..24b50003e3c 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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 @@ -136,8 +136,7 @@ final class LCMS implements PCMM { static native void colorConvert(long trans, int width, int height, int srcOffset, int srcNextRowOffset, int dstOffset, int dstNextRowOffset, - Object srcData, Object dstData, - int srcType, int dstType); + Object srcData, Object dstData); private LCMS() {} diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java index 663e11ff172..c7bae875282 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java @@ -31,7 +31,6 @@ import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.ComponentSampleModel; import java.awt.image.Raster; -import java.lang.annotation.Native; import java.nio.ByteOrder; import sun.awt.image.ByteComponentRaster; @@ -69,14 +68,7 @@ final class LCMSImageLayout { // private static final int PT_BGRA_8 = PT_ABGR_8 | SWAPFIRST; private static final int SWAP_ENDIAN = ByteOrder.nativeOrder() == LITTLE_ENDIAN ? DOSWAP : 0; - @Native - private static final int DT_BYTE = 0; - @Native - private static final int DT_SHORT = 1; - @Native - private static final int DT_INT = 2; int pixelType; - int dataType; int width; int height; int nextRowOffset; @@ -93,12 +85,10 @@ final class LCMSImageLayout { * @param data the storage of pixels: {@code byte[], short[] or int[]} * @param length the length of the data array * @param nc the number of color components - * @param dt the type of data array: DT_BYTE, DT_SHORT or DT_INT * @param size the size of one color component in bytes */ - private LCMSImageLayout(Object data, int length, int nc, int dt, int size) { + private LCMSImageLayout(Object data, int length, int nc, int size) { dataArray = data; - dataType = dt; dataArrayLength = length * size; pixelType = CHANNELS_SH(nc) | BYTES_SH(size); width = length / nc; @@ -109,11 +99,11 @@ final class LCMSImageLayout { } LCMSImageLayout(byte[] data, int nc) { - this(data, data.length, nc, DT_BYTE, Byte.BYTES); + this(data, data.length, nc, Byte.BYTES); } LCMSImageLayout(short[] data, int nc) { - this(data, data.length, nc, DT_SHORT, Short.BYTES); + this(data, data.length, nc, Short.BYTES); } private LCMSImageLayout() { @@ -186,7 +176,6 @@ final class LCMSImageLayout { l.offset = safeMult(4, intRaster.getDataOffset(0)); l.dataArray = intRaster.getDataStorage(); l.dataArrayLength = 4 * intRaster.getDataStorage().length; - l.dataType = DT_INT; } case BufferedImage.TYPE_BYTE_GRAY, BufferedImage.TYPE_3BYTE_BGR, BufferedImage.TYPE_4BYTE_ABGR, @@ -201,7 +190,6 @@ final class LCMSImageLayout { l.offset = byteRaster.getDataOffset(firstBand); l.dataArray = byteRaster.getDataStorage(); l.dataArrayLength = byteRaster.getDataStorage().length; - l.dataType = DT_BYTE; } case BufferedImage.TYPE_USHORT_GRAY -> { if (!(raster instanceof ShortComponentRaster shortRaster)) { @@ -212,7 +200,6 @@ final class LCMSImageLayout { l.offset = safeMult(2, shortRaster.getDataOffset(0)); l.dataArray = shortRaster.getDataStorage(); l.dataArrayLength = 2 * shortRaster.getDataStorage().length; - l.dataType = DT_SHORT; } default -> { return null; @@ -319,7 +306,6 @@ final class LCMSImageLayout { l.nextPixelOffset = br.getPixelStride(); l.offset = br.getDataOffset(firstBand); - l.dataType = DT_BYTE; byte[] data = br.getDataStorage(); l.dataArray = data; l.dataArrayLength = data.length; diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java index 881a6556ace..3f4f510cf94 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java @@ -121,8 +121,7 @@ final class LCMSTransform implements ColorTransform { } LCMS.colorConvert(tfm.ID, in.width, in.height, in.offset, in.nextRowOffset, out.offset, out.nextRowOffset, - in.dataArray, out.dataArray, - in.dataType, out.dataType); + in.dataArray, out.dataArray); Reference.reachabilityFence(tfm); // prevent deallocation of "tfm.ID" } diff --git a/src/java.desktop/share/legal/libpng.md b/src/java.desktop/share/legal/libpng.md index d43ccf2e8e4..8899491c6c0 100644 --- a/src/java.desktop/share/legal/libpng.md +++ b/src/java.desktop/share/legal/libpng.md @@ -1,4 +1,4 @@ -## libpng v1.6.47 +## libpng v1.6.51 ### libpng License

    @@ -9,7 +9,7 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
     PNG Reference Library License version 2
     ---------------------------------------
     
    -Copyright (c) 1995-2025 The PNG Reference Library Authors.
    +Copyright (C) 1995-2025 The PNG Reference Library Authors.
     Copyright (C) 2018-2025 Cosmin Truta
     Copyright (C) 1998-2018 Glenn Randers-Pehrson
     Copyright (C) 1996-1997 Andreas Dilger
    @@ -173,6 +173,7 @@ Authors, for copyright and licensing purposes.
      * Lucas Chollet
      * Magnus Holmgren
      * Mandar Sahastrabuddhe
    + * Manfred Schlaegl
      * Mans Rullgard
      * Matt Sarett
      * Mike Klein
    @@ -184,6 +185,7 @@ Authors, for copyright and licensing purposes.
      * Samuel Williams
      * Simon-Pierre Cadieux
      * Tim Wegner
    + * Tobias Stoeckmann
      * Tom Lane
      * Tom Tanner
      * Vadim Barkov
    @@ -193,8 +195,9 @@ Authors, for copyright and licensing purposes.
         - Zixu Wang (王子旭)
      * Arm Holdings
         - Richard Townsend
    - * Google Inc.
    + * Google LLC
         - Dan Field
    +    - Dragoș Tiselice
         - Leon Scroggins III
         - Matt Sarett
         - Mike Klein
    @@ -204,6 +207,8 @@ Authors, for copyright and licensing purposes.
         - GuXiWei (顾希伟)
         - JinBo (金波)
         - ZhangLixia (张利霞)
    + * Samsung Group
    +    - Filip Wasil
     
     The build projects, the build scripts, the test scripts, and other
     files in the "projects", "scripts" and "tests" directories, have
    @@ -214,3 +219,4 @@ of the tools-generated files that are distributed with libpng, have
     other copyright owners, and are released under other open source
     licenses.
     ```
    +
    diff --git a/src/java.desktop/share/native/liblcms/LCMS.c b/src/java.desktop/share/native/liblcms/LCMS.c
    index 5cf7ee6c436..5d4ace7a624 100644
    --- a/src/java.desktop/share/native/liblcms/LCMS.c
    +++ b/src/java.desktop/share/native/liblcms/LCMS.c
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2007, 2025, 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,7 +27,6 @@
     #include 
     #include 
     #include "sun_java2d_cmm_lcms_LCMS.h"
    -#include "sun_java2d_cmm_lcms_LCMSImageLayout.h"
     #include "jni_util.h"
     #include "Trace.h"
     #include "Disposer.h"
    @@ -46,10 +45,6 @@
     
     #define SigHead TagIdConst('h','e','a','d')
     
    -#define DT_BYTE     sun_java2d_cmm_lcms_LCMSImageLayout_DT_BYTE
    -#define DT_SHORT    sun_java2d_cmm_lcms_LCMSImageLayout_DT_SHORT
    -#define DT_INT      sun_java2d_cmm_lcms_LCMSImageLayout_DT_INT
    -
     /* Default temp profile list size */
     #define DF_ICC_BUF_SIZE 32
     
    @@ -464,46 +459,17 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative
         }
     }
     
    -static void *getILData(JNIEnv *env, jobject data, jint type) {
    -    switch (type) {
    -        case DT_BYTE:
    -            return (*env)->GetByteArrayElements(env, data, 0);
    -        case DT_SHORT:
    -            return (*env)->GetShortArrayElements(env, data, 0);
    -        case DT_INT:
    -            return (*env)->GetIntArrayElements(env, data, 0);
    -        default:
    -            return NULL;
    -    }
    -}
    -
    -static void releaseILData(JNIEnv *env, void *pData, jint type, jobject data,
    -                          jint mode) {
    -    switch (type) {
    -        case DT_BYTE:
    -            (*env)->ReleaseByteArrayElements(env, data, (jbyte *) pData, mode);
    -            break;
    -        case DT_SHORT:
    -            (*env)->ReleaseShortArrayElements(env, data, (jshort *) pData, mode);
    -            break;
    -        case DT_INT:
    -            (*env)->ReleaseIntArrayElements(env, data, (jint *) pData, mode);
    -            break;
    -    }
    -}
    -
     /*
      * Class:     sun_java2d_cmm_lcms_LCMS
      * Method:    colorConvert
    - * Signature: (JIIIIIIZZLjava/lang/Object;Ljava/lang/Object;)V
    + * Signature: (JIIIIIILjava/lang/Object;Ljava/lang/Object;)V
      */
     JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert
       (JNIEnv *env, jclass cls, jlong ID, jint width, jint height, jint srcOffset,
        jint srcNextRowOffset, jint dstOffset, jint dstNextRowOffset,
    -   jobject srcData, jobject dstData, jint srcDType, jint dstDType)
    +   jobject srcData, jobject dstData)
     {
         cmsHTRANSFORM sTrans = jlong_to_ptr(ID);
    -
         if (sTrans == NULL) {
             J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL");
             JNU_ThrowByName(env, "java/awt/color/CMMException",
    @@ -511,28 +477,22 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert
             return;
         }
     
    -    void *inputBuffer = getILData(env, srcData, srcDType);
    +    void *inputBuffer = (*env)->GetPrimitiveArrayCritical(env, srcData, NULL);
         if (inputBuffer == NULL) {
    -        J2dRlsTraceLn(J2D_TRACE_ERROR, "");
             // An exception should have already been thrown.
             return;
         }
    +    void *outputBuffer = (*env)->GetPrimitiveArrayCritical(env, dstData, NULL);
    +    if (outputBuffer != NULL) {
    +        char *input = (char *) inputBuffer + srcOffset;
    +        char *output = (char *) outputBuffer + dstOffset;
     
    -    void *outputBuffer = getILData(env, dstData, dstDType);
    -    if (outputBuffer == NULL) {
    -        releaseILData(env, inputBuffer, srcDType, srcData, JNI_ABORT);
    -        // An exception should have already been thrown.
    -        return;
    +        cmsDoTransformLineStride(sTrans, input, output, width, height,
    +                                 srcNextRowOffset, dstNextRowOffset, 0, 0);
    +
    +        (*env)->ReleasePrimitiveArrayCritical(env, dstData, outputBuffer, 0);
         }
    -
    -    char *input = (char *) inputBuffer + srcOffset;
    -    char *output = (char *) outputBuffer + dstOffset;
    -
    -    cmsDoTransformLineStride(sTrans, input, output, width, height,
    -                             srcNextRowOffset, dstNextRowOffset, 0, 0);
    -
    -    releaseILData(env, inputBuffer, srcDType, srcData, JNI_ABORT);
    -    releaseILData(env, outputBuffer, dstDType, dstData, 0);
    +    (*env)->ReleasePrimitiveArrayCritical(env, srcData, inputBuffer, JNI_ABORT);
     }
     
     static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
    index 834b5e19277..2478fd0fc08 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
    @@ -6251,6 +6251,59 @@ Version 1.6.47 [February 18, 2025]
         colorspace precedence rules, due to pre-existing colorspace checks.
         (Reported by Bob Friesenhahn; fixed by John Bowler)
     
    +Version 1.6.48 [April 30, 2025]
    +  Fixed the floating-point version of the mDCv setter `png_set_mDCv`.
    +    (Reported by Mohit Bakshi; fixed by John Bowler)
    +  Added #error directives to discourage the inclusion of private
    +    libpng implementation header files in PNG-supporting applications.
    +  Added the CMake build option `PNG_LIBCONF_HEADER`, to be used as an
    +    alternative to `DFA_XTRA`.
    +  Removed the Travis CI configuration files, with heartfelt thanks for
    +    their generous support of our project over the past five years!
    +
    +Version 1.6.49 [June 12, 2025]
    +  Added SIMD-optimized code for the RISC-V Vector Extension (RVV).
    +    (Contributed by Manfred Schlaegl, Dragos Tiselice and Filip Wasil)
    +  Added various fixes and improvements to the build scripts and to
    +    the sample code.
    +
    +Version 1.6.50 [July 1, 2025]
    +  Improved the detection of the RVV Extension on the RISC-V platform.
    +    (Contributed by Filip Wasil)
    +  Replaced inline ASM with C intrinsics in the RVV code.
    +    (Contributed by Filip Wasil)
    +  Fixed a decoder defect in which unknown chunks trailing IDAT, set
    +    to go through the unknown chunk handler, incorrectly triggered
    +    out-of-place IEND errors.
    +    (Contributed by John Bowler)
    +  Fixed the CMake file for cross-platform builds that require `libm`.
    +
    +Version 1.6.51 [November 21, 2025]
    +  Fixed CVE-2025-64505 (moderate severity):
    +    Heap buffer overflow in `png_do_quantize` via malformed palette index.
    +    (Reported by Samsung; analyzed by Fabio Gritti.)
    +  Fixed CVE-2025-64506 (moderate severity):
    +    Heap buffer over-read in `png_write_image_8bit` with 8-bit input and
    +    `convert_to_8bit` enabled.
    +    (Reported by Samsung and ;
    +    analyzed by Fabio Gritti.)
    +  Fixed CVE-2025-64720 (high severity):
    +    Buffer overflow in `png_image_read_composite` via incorrect palette
    +    premultiplication.
    +    (Reported by Samsung; analyzed by John Bowler.)
    +  Fixed CVE-2025-65018 (high severity):
    +    Heap buffer overflow in `png_combine_row` triggered via
    +    `png_image_finish_read`.
    +    (Reported by .)
    +  Fixed a memory leak in `png_set_quantize`.
    +    (Reported by Samsung; analyzed by Fabio Gritti.)
    +  Removed the experimental and incomplete ERROR_NUMBERS code.
    +    (Contributed by Tobias Stoeckmann.)
    +  Improved the RISC-V vector extension support; required RVV 1.0 or newer.
    +    (Contributed by Filip Wasil.)
    +  Added GitHub Actions workflows for automated testing.
    +  Performed various refactorings and cleanups.
    +
     Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
     Subscription is required; visit
     https://lists.sourceforge.net/lists/listinfo/png-mng-implement
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/README b/src/java.desktop/share/native/libsplashscreen/libpng/README
    index 57952fb215a..5ea329ee3da 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.47
    +README for libpng version 1.6.51
     ================================
     
     See the note about version numbers near the top of `png.h`.
    @@ -147,6 +147,7 @@ Files included in this distribution
         loongarch/    =>  Optimized code for LoongArch LSX
         mips/         =>  Optimized code for MIPS MSA and MIPS MMI
         powerpc/      =>  Optimized code for PowerPC VSX
    +    riscv/        =>  Optimized code for the RISC-V platform
         ci/           =>  Scripts for continuous integration
         contrib/      =>  External contributions
             arm-neon/     =>  Optimized code for the ARM-NEON platform
    @@ -162,6 +163,7 @@ Files included in this distribution
                               programs demonstrating the use of pngusr.dfa
             pngminus/     =>  Simple pnm2png and png2pnm programs
             pngsuite/     =>  Test images
    +        riscv-rvv/    =>  Optimized code for the RISC-V Vector platform
             testpngs/     =>  Test images
             tools/        =>  Various tools
             visupng/      =>  VisualPng, a Windows viewer for PNG images
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.c b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
    index 7b6de2f8ec3..7d85e7c8d5f 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_47 Your_png_h_is_not_version_1_6_47;
    +typedef png_libpng_version_1_6_51 Your_png_h_is_not_version_1_6_51;
     
     /* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
      * corresponding macro definitions.  This causes a compile time failure if
    @@ -137,10 +137,16 @@ png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
        if (png_ptr == NULL)
           return NULL;
     
    -   if (items >= (~(png_alloc_size_t)0)/size)
    +   /* This check against overflow is vestigial, dating back from
    +    * the old times when png_zalloc used to be an exported function.
    +    * We're still keeping it here for now, as an extra-cautious
    +    * prevention against programming errors inside zlib, although it
    +    * should rather be a debug-time assertion instead.
    +    */
    +   if (size != 0 && items >= (~(png_alloc_size_t)0) / size)
        {
    -      png_warning (png_voidcast(png_structrp, png_ptr),
    -          "Potential overflow in png_zalloc()");
    +      png_warning(png_voidcast(png_structrp, png_ptr),
    +                  "Potential overflow in png_zalloc()");
           return NULL;
        }
     
    @@ -267,10 +273,6 @@ png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver)
           png_warning(png_ptr, m);
     #endif
     
    -#ifdef PNG_ERROR_NUMBERS_SUPPORTED
    -      png_ptr->flags = 0;
    -#endif
    -
           return 0;
        }
     
    @@ -729,7 +731,7 @@ png_get_io_ptr(png_const_structrp png_ptr)
      * function of your own because "FILE *" isn't necessarily available.
      */
     void PNGAPI
    -png_init_io(png_structrp png_ptr, png_FILE_p fp)
    +png_init_io(png_structrp png_ptr, FILE *fp)
     {
        png_debug(1, "in png_init_io");
     
    @@ -844,7 +846,7 @@ png_get_copyright(png_const_structrp png_ptr)
        return PNG_STRING_COPYRIGHT
     #else
        return PNG_STRING_NEWLINE \
    -      "libpng version 1.6.47" PNG_STRING_NEWLINE \
    +      "libpng version 1.6.51" PNG_STRING_NEWLINE \
           "Copyright (c) 2018-2025 Cosmin Truta" PNG_STRING_NEWLINE \
           "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
           PNG_STRING_NEWLINE \
    @@ -1520,7 +1522,7 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
     }
     #endif /* COLORSPACE */
     
    -#ifdef PNG_iCCP_SUPPORTED
    +#ifdef PNG_READ_iCCP_SUPPORTED
     /* Error message generation */
     static char
     png_icc_tag_char(png_uint_32 byte)
    @@ -1596,9 +1598,7 @@ png_icc_profile_error(png_const_structrp png_ptr, png_const_charp name,
     
        return 0;
     }
    -#endif /* iCCP */
     
    -#ifdef PNG_READ_iCCP_SUPPORTED
     /* Encoded value of D50 as an ICC XYZNumber.  From the ICC 2010 spec the value
      * is XYZ(0.9642,1.0,0.8249), which scales to:
      *
    @@ -3998,7 +3998,7 @@ png_image_free_function(png_voidp argument)
     #  ifdef PNG_STDIO_SUPPORTED
           if (cp->owned_file != 0)
           {
    -         FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr);
    +         FILE *fp = png_voidcast(FILE *, cp->png_ptr->io_ptr);
              cp->owned_file = 0;
     
              /* Ignore errors here. */
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.h b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
    index ede12c34fe6..d39ff73552c 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.47
    + * libpng version 1.6.51
      *
      * Copyright (c) 2018-2025 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.47, February 2025:
    + *   libpng versions 1.6.36, December 2018, through 1.6.51, November 2025:
      *     Cosmin Truta
      *   See also "Contributing Authors", below.
      */
    @@ -267,7 +267,7 @@
      *    ...
      *    1.5.30                  15    10530  15.so.15.30[.0]
      *    ...
    - *    1.6.47                  16    10647  16.so.16.47[.0]
    + *    1.6.51                  16    10651  16.so.16.51[.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.47"
    +#define PNG_LIBPNG_VER_STRING "1.6.51"
     #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 47
    +#define PNG_LIBPNG_VER_RELEASE 51
     
     /* 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 10647 /* 1.6.47 */
    +#define PNG_LIBPNG_VER 10651 /* 1.6.51 */
     
     /* 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_47;
    +typedef char* png_libpng_version_1_6_51;
     
     /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
      *
    @@ -1599,7 +1599,7 @@ PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,
     
     #ifdef PNG_STDIO_SUPPORTED
     /* Initialize the input/output for the PNG file to the default functions. */
    -PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp));
    +PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, FILE *fp));
     #endif
     
     /* Replace the (error and abort), and warning functions with user
    @@ -3117,7 +3117,7 @@ PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image,
         */
     
     PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image,
    -   FILE* file));
    +   FILE *file));
        /* The PNG header is read from the stdio FILE object. */
     #endif /* STDIO */
     
    @@ -3192,7 +3192,7 @@ PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image,
     PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file,
        int convert_to_8_bit, const void *buffer, png_int_32 row_stride,
        const void *colormap));
    -   /* Write the image to the given (FILE*). */
    +   /* Write the image to the given FILE object. */
     #endif /* SIMPLIFIED_WRITE_STDIO */
     
     /* With all write APIs if image is in one of the linear formats with 16-bit
    @@ -3332,26 +3332,45 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory,
      *           selected at run time.
      */
     #ifdef PNG_SET_OPTION_SUPPORTED
    +
    +/* HARDWARE: ARM Neon SIMD instructions supported */
     #ifdef PNG_ARM_NEON_API_SUPPORTED
    -#  define PNG_ARM_NEON   0 /* HARDWARE: ARM Neon SIMD instructions supported */
    -#endif
    -#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */
    -#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */
    -#ifdef PNG_MIPS_MSA_API_SUPPORTED
    -#  define PNG_MIPS_MSA   6 /* HARDWARE: MIPS Msa SIMD instructions supported */
    -#endif
    -#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
    -#  define PNG_IGNORE_ADLER32 8 /* SOFTWARE: disable Adler32 check on IDAT */
    -#endif
    -#ifdef PNG_POWERPC_VSX_API_SUPPORTED
    -#  define PNG_POWERPC_VSX   10 /* HARDWARE: PowerPC VSX SIMD instructions
    -                                * supported */
    -#endif
    -#ifdef PNG_MIPS_MMI_API_SUPPORTED
    -#  define PNG_MIPS_MMI   12 /* HARDWARE: MIPS MMI SIMD instructions supported */
    +#  define PNG_ARM_NEON 0
     #endif
     
    -#define PNG_OPTION_NEXT  14 /* Next option - numbers must be even */
    +/* SOFTWARE: Force maximum window */
    +#define PNG_MAXIMUM_INFLATE_WINDOW 2
    +
    +/* SOFTWARE: Check ICC profile for sRGB */
    +#define PNG_SKIP_sRGB_CHECK_PROFILE 4
    +
    +/* HARDWARE: MIPS MSA SIMD instructions supported */
    +#ifdef PNG_MIPS_MSA_API_SUPPORTED
    +#  define PNG_MIPS_MSA 6
    +#endif
    +
    +/* SOFTWARE: Disable Adler32 check on IDAT */
    +#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
    +#  define PNG_IGNORE_ADLER32 8
    +#endif
    +
    +/* HARDWARE: PowerPC VSX SIMD instructions supported */
    +#ifdef PNG_POWERPC_VSX_API_SUPPORTED
    +#  define PNG_POWERPC_VSX 10
    +#endif
    +
    +/* HARDWARE: MIPS MMI SIMD instructions supported */
    +#ifdef PNG_MIPS_MMI_API_SUPPORTED
    +#  define PNG_MIPS_MMI 12
    +#endif
    +
    +/* HARDWARE: RISC-V RVV SIMD instructions supported */
    +#ifdef PNG_RISCV_RVV_API_SUPPORTED
    +#  define PNG_RISCV_RVV 14
    +#endif
    +
    +/* Next option - numbers must be even */
    +#define PNG_OPTION_NEXT 16
     
     /* Return values: NOTE: there are four values and 'off' is *not* zero */
     #define PNG_OPTION_UNSET   0 /* Unset - defaults to off */
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
    index 70bca6fa1c9..4bc5f7bb468 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.47
    + * libpng version 1.6.51
      *
      * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
    @@ -248,25 +248,13 @@
       /* NOTE: PNGCBAPI always defaults to PNGCAPI. */
     
     #  if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD)
    -#     error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed"
    +#     error PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed
     #  endif
     
    -#  if (defined(_MSC_VER) && _MSC_VER < 800) ||\
    -      (defined(__BORLANDC__) && __BORLANDC__ < 0x500)
    -   /* older Borland and MSC
    -    * compilers used '__export' and required this to be after
    -    * the type.
    -    */
    -#    ifndef PNG_EXPORT_TYPE
    -#      define PNG_EXPORT_TYPE(type) type PNG_IMPEXP
    -#    endif
    -#    define PNG_DLL_EXPORT __export
    -#  else /* newer compiler */
    -#    define PNG_DLL_EXPORT __declspec(dllexport)
    -#    ifndef PNG_DLL_IMPORT
    -#      define PNG_DLL_IMPORT __declspec(dllimport)
    -#    endif
    -#  endif /* compiler */
    +#  define PNG_DLL_EXPORT __declspec(dllexport)
    +#  ifndef PNG_DLL_IMPORT
    +#    define PNG_DLL_IMPORT __declspec(dllimport)
    +#  endif
     
     #else /* !Windows */
     #  if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)
    @@ -508,7 +496,7 @@
     #if CHAR_BIT == 8 && UCHAR_MAX == 255
        typedef unsigned char png_byte;
     #else
    -#  error "libpng requires 8-bit bytes"
    +#  error libpng requires 8-bit bytes
     #endif
     
     #if INT_MIN == -32768 && INT_MAX == 32767
    @@ -516,7 +504,7 @@
     #elif SHRT_MIN == -32768 && SHRT_MAX == 32767
        typedef short png_int_16;
     #else
    -#  error "libpng requires a signed 16-bit type"
    +#  error libpng requires a signed 16-bit integer type
     #endif
     
     #if UINT_MAX == 65535
    @@ -524,7 +512,7 @@
     #elif USHRT_MAX == 65535
        typedef unsigned short png_uint_16;
     #else
    -#  error "libpng requires an unsigned 16-bit type"
    +#  error libpng requires an unsigned 16-bit integer type
     #endif
     
     #if INT_MIN < -2147483646 && INT_MAX > 2147483646
    @@ -532,7 +520,7 @@
     #elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646
        typedef long int png_int_32;
     #else
    -#  error "libpng requires a signed 32-bit (or more) type"
    +#  error libpng requires a signed 32-bit (or longer) integer type
     #endif
     
     #if UINT_MAX > 4294967294U
    @@ -540,7 +528,7 @@
     #elif ULONG_MAX > 4294967294U
        typedef unsigned long int png_uint_32;
     #else
    -#  error "libpng requires an unsigned 32-bit (or more) type"
    +#  error libpng requires an unsigned 32-bit (or longer) integer type
     #endif
     
     /* Prior to 1.6.0, it was possible to disable the use of size_t and ptrdiff_t.
    @@ -621,10 +609,6 @@ typedef const png_fixed_point * png_const_fixed_point_p;
     typedef size_t                * png_size_tp;
     typedef const size_t          * png_const_size_tp;
     
    -#ifdef PNG_STDIO_SUPPORTED
    -typedef FILE            * png_FILE_p;
    -#endif
    -
     #ifdef PNG_FLOATING_POINT_SUPPORTED
     typedef double       * png_doublep;
     typedef const double * png_const_doublep;
    @@ -646,6 +630,15 @@ typedef double          * * png_doublepp;
     /* Pointers to pointers to pointers; i.e., pointer to array */
     typedef char            * * * png_charppp;
     
    +#ifdef PNG_STDIO_SUPPORTED
    +/* With PNG_STDIO_SUPPORTED it was possible to use I/O streams that were
    + * not necessarily stdio FILE streams, to allow building Windows applications
    + * before Win32 and Windows CE applications before WinCE 3.0, but that kind
    + * of support has long been discontinued.
    + */
    +typedef FILE            * png_FILE_p; /* [Deprecated] */
    +#endif
    +
     #endif /* PNG_BUILDING_SYMBOL_TABLE */
     
     #endif /* PNGCONF_H */
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h
    index 8eb5400ea9a..6ea2644dfcd 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngdebug.h
    @@ -22,14 +22,14 @@
      * questions.
      */
     
    -/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c
    +/* pngdebug.h - internal debugging macros for libpng
      *
      * This file is available under and governed by the GNU General Public
      * License version 2 only, as published by the Free Software Foundation.
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -39,6 +39,10 @@
      * and license in png.h
      */
     
    +#ifndef PNGPRIV_H
    +#  error This file must not be included by applications; please include 
    +#endif
    +
     /* Define PNG_DEBUG at compile time for debugging information.  Higher
      * numbers for PNG_DEBUG mean more debugging information.  This has
      * only been added since version 0.95 so it is not implemented throughout
    @@ -63,9 +67,6 @@
     #define PNGDEBUG_H
     /* These settings control the formatting of messages in png.c and pngerror.c */
     /* Moved to pngdebug.h at 1.5.0 */
    -#  ifndef PNG_LITERAL_SHARP
    -#    define PNG_LITERAL_SHARP 0x23
    -#  endif
     #  ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET
     #    define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b
     #  endif
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
    index ea0103331d3..44c86ebfef9 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -68,46 +68,6 @@ PNG_FUNCTION(void,PNGAPI
     png_error,(png_const_structrp png_ptr, png_const_charp error_message),
         PNG_NORETURN)
     {
    -#ifdef PNG_ERROR_NUMBERS_SUPPORTED
    -   char msg[16];
    -   if (png_ptr != NULL)
    -   {
    -      if ((png_ptr->flags &
    -         (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
    -      {
    -         if (*error_message == PNG_LITERAL_SHARP)
    -         {
    -            /* Strip "#nnnn " from beginning of error message. */
    -            int offset;
    -            for (offset = 1; offset<15; offset++)
    -               if (error_message[offset] == ' ')
    -                  break;
    -
    -            if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
    -            {
    -               int i;
    -               for (i = 0; i < offset - 1; i++)
    -                  msg[i] = error_message[i + 1];
    -               msg[i - 1] = '\0';
    -               error_message = msg;
    -            }
    -
    -            else
    -               error_message += offset;
    -         }
    -
    -         else
    -         {
    -            if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
    -            {
    -               msg[0] = '0';
    -               msg[1] = '\0';
    -               error_message = msg;
    -            }
    -         }
    -      }
    -   }
    -#endif
        if (png_ptr != NULL && png_ptr->error_fn != NULL)
           (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr),
               error_message);
    @@ -245,21 +205,6 @@ void PNGAPI
     png_warning(png_const_structrp png_ptr, png_const_charp warning_message)
     {
        int offset = 0;
    -   if (png_ptr != NULL)
    -   {
    -#ifdef PNG_ERROR_NUMBERS_SUPPORTED
    -   if ((png_ptr->flags &
    -       (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
    -#endif
    -      {
    -         if (*warning_message == PNG_LITERAL_SHARP)
    -         {
    -            for (offset = 1; offset < 15; offset++)
    -               if (warning_message[offset] == ' ')
    -                  break;
    -         }
    -      }
    -   }
        if (png_ptr != NULL && png_ptr->warning_fn != NULL)
           (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr),
               warning_message + offset);
    @@ -741,42 +686,9 @@ png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
         PNG_NORETURN)
     {
     #ifdef PNG_CONSOLE_IO_SUPPORTED
    -#ifdef PNG_ERROR_NUMBERS_SUPPORTED
    -   /* Check on NULL only added in 1.5.4 */
    -   if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)
    -   {
    -      /* Strip "#nnnn " from beginning of error message. */
    -      int offset;
    -      char error_number[16];
    -      for (offset = 0; offset<15; offset++)
    -      {
    -         error_number[offset] = error_message[offset + 1];
    -         if (error_message[offset] == ' ')
    -            break;
    -      }
    -
    -      if ((offset > 1) && (offset < 15))
    -      {
    -         error_number[offset - 1] = '\0';
    -         fprintf(stderr, "libpng error no. %s: %s",
    -             error_number, error_message + offset + 1);
    -         fprintf(stderr, PNG_STRING_NEWLINE);
    -      }
    -
    -      else
    -      {
    -         fprintf(stderr, "libpng error: %s, offset=%d",
    -             error_message, offset);
    -         fprintf(stderr, PNG_STRING_NEWLINE);
    -      }
    -   }
    -   else
    -#endif
    -   {
    -      fprintf(stderr, "libpng error: %s", error_message ? error_message :
    -         "undefined");
    -      fprintf(stderr, PNG_STRING_NEWLINE);
    -   }
    +   fprintf(stderr, "libpng error: %s", error_message ? error_message :
    +      "undefined");
    +   fprintf(stderr, PNG_STRING_NEWLINE);
     #else
        PNG_UNUSED(error_message) /* Make compiler happy */
     #endif
    @@ -814,40 +726,8 @@ static void /* PRIVATE */
     png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)
     {
     #ifdef PNG_CONSOLE_IO_SUPPORTED
    -#  ifdef PNG_ERROR_NUMBERS_SUPPORTED
    -   if (*warning_message == PNG_LITERAL_SHARP)
    -   {
    -      int offset;
    -      char warning_number[16];
    -      for (offset = 0; offset < 15; offset++)
    -      {
    -         warning_number[offset] = warning_message[offset + 1];
    -         if (warning_message[offset] == ' ')
    -            break;
    -      }
    -
    -      if ((offset > 1) && (offset < 15))
    -      {
    -         warning_number[offset + 1] = '\0';
    -         fprintf(stderr, "libpng warning no. %s: %s",
    -             warning_number, warning_message + offset);
    -         fprintf(stderr, PNG_STRING_NEWLINE);
    -      }
    -
    -      else
    -      {
    -         fprintf(stderr, "libpng warning: %s",
    -             warning_message);
    -         fprintf(stderr, PNG_STRING_NEWLINE);
    -      }
    -   }
    -   else
    -#  endif
    -
    -   {
    -      fprintf(stderr, "libpng warning: %s", warning_message);
    -      fprintf(stderr, PNG_STRING_NEWLINE);
    -   }
    +   fprintf(stderr, "libpng warning: %s", warning_message);
    +   fprintf(stderr, PNG_STRING_NEWLINE);
     #else
        PNG_UNUSED(warning_message) /* Make compiler happy */
     #endif
    @@ -895,12 +775,8 @@ png_get_error_ptr(png_const_structrp png_ptr)
     void PNGAPI
     png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)
     {
    -   if (png_ptr != NULL)
    -   {
    -      png_ptr->flags &=
    -         ((~(PNG_FLAG_STRIP_ERROR_NUMBERS |
    -         PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
    -   }
    +   PNG_UNUSED(png_ptr)
    +   PNG_UNUSED(strip_mode)
     }
     #endif
     
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
    index d67adbae247..ed2e7f886f5 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h
    index bc6ed3d09c9..c79c6cc780f 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnginfo.h
    @@ -22,14 +22,14 @@
      * questions.
      */
     
    -/* pnginfo.h - header file for PNG reference library
    +/* pnginfo.h - internal structures for libpng
      *
      * This file is available under and governed by the GNU General Public
      * License version 2 only, as published by the Free Software Foundation.
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2013,2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -39,43 +39,20 @@
      * and license in png.h
      */
     
    - /* png_info is a structure that holds the information in a PNG file so
    - * that the application can find out the characteristics of the image.
    - * If you are reading the file, this structure will tell you what is
    - * in the PNG file.  If you are writing the file, fill in the information
    - * you want to put into the PNG file, using png_set_*() functions, then
    - * call png_write_info().
    +#ifndef PNGPRIV_H
    +#  error This file must not be included by applications; please include 
    +#endif
    +
    +/* INTERNAL, PRIVATE definition of a PNG.
      *
    - * The names chosen should be very close to the PNG specification, so
    - * consult that document for information about the meaning of each field.
    + * png_info is a modifiable description of a PNG datastream.  The fields inside
    + * this structure are accessed through png_get_() functions and modified
    + * using png_set_() functions.
      *
    - * With libpng < 0.95, it was only possible to directly set and read the
    - * the values in the png_info_struct, which meant that the contents and
    - * order of the values had to remain fixed.  With libpng 0.95 and later,
    - * however, there are now functions that abstract the contents of
    - * png_info_struct from the application, so this makes it easier to use
    - * libpng with dynamic libraries, and even makes it possible to use
    - * libraries that don't have all of the libpng ancillary chunk-handing
    - * functionality.  In libpng-1.5.0 this was moved into a separate private
    - * file that is not visible to applications.
    - *
    - * The following members may have allocated storage attached that should be
    - * cleaned up before the structure is discarded: palette, trans, text,
    - * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile,
    - * splt_palettes, scal_unit, row_pointers, and unknowns.   By default, these
    - * are automatically freed when the info structure is deallocated, if they were
    - * allocated internally by libpng.  This behavior can be changed by means
    - * of the png_data_freer() function.
    - *
    - * More allocation details: all the chunk-reading functions that
    - * change these members go through the corresponding png_set_*
    - * functions.  A function to clear these members is available: see
    - * png_free_data().  The png_set_* functions do not depend on being
    - * able to point info structure members to any of the storage they are
    - * passed (they make their own copies), EXCEPT that the png_set_text
    - * functions use the same storage passed to them in the text_ptr or
    - * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns
    - * functions do not make their own copies.
    + * Some functions in libpng do directly access members of png_info.  However,
    + * this should be avoided.  png_struct objects contain members which hold
    + * caches, sometimes optimised, of the values from png_info objects, and
    + * png_info is not passed to the functions which read and write image data.
      */
     #ifndef PNGINFO_H
     #define PNGINFO_H
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
    index 906f855db0e..4cfae474751 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.47 */
    +/* libpng version 1.6.51 */
     
     /* Copyright (c) 2018-2025 Cosmin Truta */
     /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
    index ba9eb4df402..12b71bcbc02 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngmem.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2014,2016 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
    index 86d0c7aaa64..3bfa913000f 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -258,6 +258,14 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
              png_benign_error(png_ptr, "Too many IDATs found");
        }
     
    +   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
    +   {
    +      /* These flags must be set consistently for all non-IDAT chunks,
    +       * including the unknown chunks.
    +       */
    +      png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT;
    +   }
    +
        if (chunk_name == png_IHDR)
        {
           if (png_ptr->push_length != 13)
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
    index 25bac4b9e69..dcd005efb34 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -48,8 +48,20 @@
      * they should be well aware of the issues that may arise from doing so.
      */
     
    +
    +/* pngpriv.h must be included first in each translation unit inside libpng.
    + * On the other hand, it must not be included at all, directly or indirectly,
    + * by any application code that uses the libpng API.
    + */
     #ifndef PNGPRIV_H
    -#define PNGPRIV_H
    +#  define PNGPRIV_H
    +#else
    +#  error Duplicate inclusion of pngpriv.h; please check the libpng source files
    +#endif
    +
    +#if defined(PNG_H) || defined(PNGCONF_H) || defined(PNGLCONF_H)
    +#  error This file must not be included by applications; please include 
    +#endif
     
     /* Feature Test Macros.  The following are defined here to ensure that correctly
      * implemented libraries reveal the APIs libpng needs to build and hide those
    @@ -86,7 +98,6 @@
      */
     #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
     #  include 
    -
        /* Pick up the definition of 'restrict' from config.h if it was read: */
     #  define PNG_RESTRICT restrict
     #endif
    @@ -96,9 +107,7 @@
      * are not internal definitions may be required.  This is handled below just
      * before png.h is included, but load the configuration now if it is available.
      */
    -#ifndef PNGLCONF_H
    -#  include "pnglibconf.h"
    -#endif
    +#include "pnglibconf.h"
     
     /* Local renames may change non-exported API functions from png.h */
     #if defined(PNG_PREFIX) && !defined(PNGPREFIX_H)
    @@ -163,6 +172,20 @@
     #  endif
     #endif
     
    +#ifndef PNG_RISCV_RVV_OPT
    +   /* RISCV_RVV optimizations are being controlled by the compiler settings,
    +    * typically the target compiler will define __riscv but the rvv extension
    +    * availability has to be explicitly stated. This is why if no
    +    * PNG_RISCV_RVV_OPT was defined then a runtime check will be executed.
    +    *
    +    * To enable RISCV_RVV optimizations unconditionally, and compile the
    +    * associated code, pass --enable-riscv-rvv=yes or --enable-riscv-rvv=on
    +    * to configure or put -DPNG_RISCV_RVV_OPT=2 in CPPFLAGS.
    +    */
    +
    +#  define PNG_RISCV_RVV_OPT 0
    +#endif
    +
     #if PNG_ARM_NEON_OPT > 0
        /* NEON optimizations are to be at least considered by libpng, so enable the
         * callbacks to do this.
    @@ -308,6 +331,16 @@
     #   define PNG_LOONGARCH_LSX_IMPLEMENTATION 0
     #endif
     
    +#if PNG_RISCV_RVV_OPT > 0 && __riscv_v >= 1000000
    +#  define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_rvv
    +#  ifndef PNG_RISCV_RVV_IMPLEMENTATION
    +      /* Use the intrinsics code by default. */
    +#     define PNG_RISCV_RVV_IMPLEMENTATION 1
    +#  endif
    +#else
    +#  define PNG_RISCV_RVV_IMPLEMENTATION 0
    +#endif /* PNG_RISCV_RVV_OPT > 0 && __riscv_v >= 1000000 */
    +
     /* Is this a build of a DLL where compilation of the object modules requires
      * different preprocessor settings to those required for a simple library?  If
      * so PNG_BUILD_DLL must be set.
    @@ -706,7 +739,7 @@
     /* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS      0x8000U */
     /* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS      0x10000U */
     #define PNG_FLAG_LIBRARY_MISMATCH        0x20000U
    -#define PNG_FLAG_STRIP_ERROR_NUMBERS     0x40000U
    +                                  /*     0x40000U    unused */
     #define PNG_FLAG_STRIP_ERROR_TEXT        0x80000U
     #define PNG_FLAG_BENIGN_ERRORS_WARN     0x100000U /* Added to libpng-1.4.0 */
     #define PNG_FLAG_APP_WARNINGS_WARN      0x200000U /* Added to libpng-1.6.0 */
    @@ -1020,17 +1053,15 @@
      * must match that used in the build, or we must be using pnglibconf.h.prebuilt:
      */
     #if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM
    -#  error ZLIB_VERNUM != PNG_ZLIB_VERNUM \
    -      "-I (include path) error: see the notes in pngpriv.h"
    -   /* This means that when pnglibconf.h was built the copy of zlib.h that it
    -    * used is not the same as the one being used here.  Because the build of
    -    * libpng makes decisions to use inflateInit2 and inflateReset2 based on the
    -    * zlib version number and because this affects handling of certain broken
    -    * PNG files the -I directives must match.
    +#  error The include path of  is incorrect
    +   /* When pnglibconf.h was built, the copy of zlib.h that it used was not the
    +    * same as the one being used here.  Considering how libpng makes decisions
    +    * to use the zlib API based on the zlib version number, the -I options must
    +    * match.
         *
    -    * The most likely explanation is that you passed a -I in CFLAGS. This will
    -    * not work; all the preprocessor directives and in particular all the -I
    -    * directives must be in CPPFLAGS.
    +    * A possible cause of this mismatch is that you passed an -I option in
    +    * CFLAGS, which is unlikely to work.  All the preprocessor options, and all
    +    * the -I options in particular, should be in CPPFLAGS.
         */
     #endif
     
    @@ -1544,6 +1575,23 @@ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_lsx,(png_row_infop
         row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
     #endif
     
    +#if PNG_RISCV_RVV_IMPLEMENTATION == 1
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_rvv,(png_row_infop
    +    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
    +#endif
    +
     /* Choose the best filter to use and filter the row data */
     PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr,
         png_row_infop row_info),PNG_EMPTY);
    @@ -2156,6 +2204,11 @@ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_lsx,
         (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
     #endif
     
    +#  if PNG_RISCV_RVV_IMPLEMENTATION == 1
    +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_rvv,
    +   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
    +#endif
    +
     PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr,
        png_const_charp key, png_bytep new_key), PNG_EMPTY);
     
    @@ -2191,4 +2244,3 @@ PNG_INTERNAL_FUNCTION(int,
     #endif
     
     #endif /* PNG_VERSION_INFO_ONLY */
    -#endif /* PNGPRIV_H */
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
    index 8a6381e1b3e..b53668a09ce 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
    @@ -731,7 +731,12 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
           png_uint_32 chunk_name = png_ptr->chunk_name;
     
           if (chunk_name != png_IDAT)
    -         png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
    +      {
    +         /* These flags must be set consistently for all non-IDAT chunks,
    +          * including the unknown chunks.
    +          */
    +         png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT;
    +      }
     
           if (chunk_name == png_IEND)
              png_handle_chunk(png_ptr, info_ptr, length);
    @@ -838,7 +843,8 @@ png_read_destroy(png_structrp png_ptr)
     #endif
     
     #if defined(PNG_READ_EXPAND_SUPPORTED) && \
    -    defined(PNG_ARM_NEON_IMPLEMENTATION)
    +    (defined(PNG_ARM_NEON_IMPLEMENTATION) || \
    +     defined(PNG_RISCV_RVV_IMPLEMENTATION))
        png_free(png_ptr, png_ptr->riffled_palette);
        png_ptr->riffled_palette = NULL;
     #endif
    @@ -1357,7 +1363,7 @@ png_image_read_header(png_voidp argument)
     
     #ifdef PNG_STDIO_SUPPORTED
     int PNGAPI
    -png_image_begin_read_from_stdio(png_imagep image, FILE* file)
    +png_image_begin_read_from_stdio(png_imagep image, FILE *file)
     {
        if (image != NULL && image->version == PNG_IMAGE_VERSION)
        {
    @@ -3152,6 +3158,54 @@ png_image_read_colormapped(png_voidp argument)
        }
     }
     
    +/* Row reading for interlaced 16-to-8 bit depth conversion with local buffer. */
    +static int
    +png_image_read_direct_scaled(png_voidp argument)
    +{
    +   png_image_read_control *display = png_voidcast(png_image_read_control*,
    +       argument);
    +   png_imagep image = display->image;
    +   png_structrp png_ptr = image->opaque->png_ptr;
    +   png_bytep local_row = png_voidcast(png_bytep, display->local_row);
    +   png_bytep first_row = png_voidcast(png_bytep, display->first_row);
    +   ptrdiff_t row_bytes = display->row_bytes;
    +   int passes;
    +
    +   /* Handle interlacing. */
    +   switch (png_ptr->interlaced)
    +   {
    +      case PNG_INTERLACE_NONE:
    +         passes = 1;
    +         break;
    +
    +      case PNG_INTERLACE_ADAM7:
    +         passes = PNG_INTERLACE_ADAM7_PASSES;
    +         break;
    +
    +      default:
    +         png_error(png_ptr, "unknown interlace type");
    +   }
    +
    +   /* Read each pass using local_row as intermediate buffer. */
    +   while (--passes >= 0)
    +   {
    +      png_uint_32 y = image->height;
    +      png_bytep output_row = first_row;
    +
    +      for (; y > 0; --y)
    +      {
    +         /* Read into local_row (gets transformed 8-bit data). */
    +         png_read_row(png_ptr, local_row, NULL);
    +
    +         /* Copy from local_row to user buffer. */
    +         memcpy(output_row, local_row, (size_t)row_bytes);
    +         output_row += row_bytes;
    +      }
    +   }
    +
    +   return 1;
    +}
    +
     /* Just the row reading part of png_image_read. */
     static int
     png_image_read_composite(png_voidp argument)
    @@ -3570,6 +3624,7 @@ png_image_read_direct(png_voidp argument)
        int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0;
        int do_local_compose = 0;
        int do_local_background = 0; /* to avoid double gamma correction bug */
    +   int do_local_scale = 0; /* for interlaced 16-to-8 bit conversion */
        int passes = 0;
     
        /* Add transforms to ensure the correct output format is produced then check
    @@ -3703,8 +3758,16 @@ png_image_read_direct(png_voidp argument)
                 png_set_expand_16(png_ptr);
     
              else /* 8-bit output */
    +         {
                 png_set_scale_16(png_ptr);
     
    +            /* For interlaced images, use local_row buffer to avoid overflow
    +             * in png_combine_row() which writes using IHDR bit-depth.
    +             */
    +            if (png_ptr->interlaced != 0)
    +               do_local_scale = 1;
    +         }
    +
              change &= ~PNG_FORMAT_FLAG_LINEAR;
           }
     
    @@ -3980,6 +4043,24 @@ png_image_read_direct(png_voidp argument)
           return result;
        }
     
    +   else if (do_local_scale != 0)
    +   {
    +      /* For interlaced 16-to-8 conversion, use an intermediate row buffer
    +       * to avoid buffer overflows in png_combine_row. The local_row is sized
    +       * for the transformed (8-bit) output, preventing the overflow that would
    +       * occur if png_combine_row wrote 16-bit data directly to the user buffer.
    +       */
    +      int result;
    +      png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
    +
    +      display->local_row = row;
    +      result = png_safe_execute(image, png_image_read_direct_scaled, display);
    +      display->local_row = NULL;
    +      png_free(png_ptr, row);
    +
    +      return result;
    +   }
    +
        else
        {
           png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c
    index 961d010df42..50a424d0912 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrio.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -85,7 +85,7 @@ png_default_read_data(png_structp png_ptr, png_bytep data, size_t length)
        /* fread() returns 0 on error, so it is OK to store this in a size_t
         * instead of an int, which is what fread() actually returns.
         */
    -   check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr));
    +   check = fread(data, 1, length, png_voidcast(FILE *, png_ptr->io_ptr));
     
        if (check != length)
           png_error(png_ptr, "Read Error");
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
    index 4f31f8f07bc..a19615f49fe 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -57,6 +57,12 @@
     #  endif
     #endif
     
    +#ifdef PNG_RISCV_RVV_IMPLEMENTATION
    +#  if PNG_RISCV_RVV_IMPLEMENTATION == 1
    +#    define PNG_RISCV_RVV_INTRINSICS_AVAILABLE
    +#  endif
    +#endif
    +
     #ifdef PNG_READ_SUPPORTED
     
     /* Set the action on getting a CRC error for an ancillary or critical chunk. */
    @@ -524,9 +530,19 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
        {
           int i;
     
    +      /* Initialize the array to index colors.
    +       *
    +       * Ensure quantize_index can fit 256 elements (PNG_MAX_PALETTE_LENGTH)
    +       * rather than num_palette elements. This is to prevent buffer overflows
    +       * caused by malformed PNG files with out-of-range palette indices.
    +       *
    +       * Be careful to avoid leaking memory. Applications are allowed to call
    +       * this function more than once per png_struct.
    +       */
    +      png_free(png_ptr, png_ptr->quantize_index);
           png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
    -          (png_alloc_size_t)num_palette);
    -      for (i = 0; i < num_palette; i++)
    +          PNG_MAX_PALETTE_LENGTH);
    +      for (i = 0; i < PNG_MAX_PALETTE_LENGTH; i++)
              png_ptr->quantize_index[i] = (png_byte)i;
        }
     
    @@ -538,15 +554,14 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
               * Perhaps not the best solution, but good enough.
               */
     
    -         int i;
    +         png_bytep quantize_sort;
    +         int i, j;
     
    -         /* Initialize an array to sort colors */
    -         png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
    +         /* Initialize the local array to sort colors. */
    +         quantize_sort = (png_bytep)png_malloc(png_ptr,
                  (png_alloc_size_t)num_palette);
    -
    -         /* Initialize the quantize_sort array */
              for (i = 0; i < num_palette; i++)
    -            png_ptr->quantize_sort[i] = (png_byte)i;
    +            quantize_sort[i] = (png_byte)i;
     
              /* Find the least used palette entries by starting a
               * bubble sort, and running it until we have sorted
    @@ -558,19 +573,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
              for (i = num_palette - 1; i >= maximum_colors; i--)
              {
                 int done; /* To stop early if the list is pre-sorted */
    -            int j;
     
                 done = 1;
                 for (j = 0; j < i; j++)
                 {
    -               if (histogram[png_ptr->quantize_sort[j]]
    -                   < histogram[png_ptr->quantize_sort[j + 1]])
    +               if (histogram[quantize_sort[j]]
    +                   < histogram[quantize_sort[j + 1]])
                    {
                       png_byte t;
     
    -                  t = png_ptr->quantize_sort[j];
    -                  png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];
    -                  png_ptr->quantize_sort[j + 1] = t;
    +                  t = quantize_sort[j];
    +                  quantize_sort[j] = quantize_sort[j + 1];
    +                  quantize_sort[j + 1] = t;
                       done = 0;
                    }
                 }
    @@ -582,18 +596,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
              /* Swap the palette around, and set up a table, if necessary */
              if (full_quantize != 0)
              {
    -            int j = num_palette;
    +            j = num_palette;
     
                 /* Put all the useful colors within the max, but don't
                  * move the others.
                  */
                 for (i = 0; i < maximum_colors; i++)
                 {
    -               if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
    +               if ((int)quantize_sort[i] >= maximum_colors)
                    {
                       do
                          j--;
    -                  while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
    +                  while ((int)quantize_sort[j] >= maximum_colors);
     
                       palette[i] = palette[j];
                    }
    @@ -601,7 +615,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
              }
              else
              {
    -            int j = num_palette;
    +            j = num_palette;
     
                 /* Move all the used colors inside the max limit, and
                  * develop a translation table.
    @@ -609,13 +623,13 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
                 for (i = 0; i < maximum_colors; i++)
                 {
                    /* Only move the colors we need to */
    -               if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
    +               if ((int)quantize_sort[i] >= maximum_colors)
                    {
                       png_color tmp_color;
     
                       do
                          j--;
    -                  while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
    +                  while ((int)quantize_sort[j] >= maximum_colors);
     
                       tmp_color = palette[j];
                       palette[j] = palette[i];
    @@ -653,8 +667,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
                    }
                 }
              }
    -         png_free(png_ptr, png_ptr->quantize_sort);
    -         png_ptr->quantize_sort = NULL;
    +         png_free(png_ptr, quantize_sort);
           }
           else
           {
    @@ -1797,19 +1810,51 @@ png_init_read_transformations(png_structrp png_ptr)
                       }
                       else /* if (png_ptr->trans_alpha[i] != 0xff) */
                       {
    -                     png_byte v, w;
    +                     if ((png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0)
    +                     {
    +                        /* Premultiply only:
    +                         * component = round((component * alpha) / 255)
    +                         */
    +                        png_uint_32 component;
     
    -                     v = png_ptr->gamma_to_1[palette[i].red];
    -                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);
    -                     palette[i].red = png_ptr->gamma_from_1[w];
    +                        component = png_ptr->gamma_to_1[palette[i].red];
    +                        component =
    +                            (component * png_ptr->trans_alpha[i] + 128) / 255;
    +                        palette[i].red = png_ptr->gamma_from_1[component];
     
    -                     v = png_ptr->gamma_to_1[palette[i].green];
    -                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);
    -                     palette[i].green = png_ptr->gamma_from_1[w];
    +                        component = png_ptr->gamma_to_1[palette[i].green];
    +                        component =
    +                            (component * png_ptr->trans_alpha[i] + 128) / 255;
    +                        palette[i].green = png_ptr->gamma_from_1[component];
     
    -                     v = png_ptr->gamma_to_1[palette[i].blue];
    -                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);
    -                     palette[i].blue = png_ptr->gamma_from_1[w];
    +                        component = png_ptr->gamma_to_1[palette[i].blue];
    +                        component =
    +                            (component * png_ptr->trans_alpha[i] + 128) / 255;
    +                        palette[i].blue = png_ptr->gamma_from_1[component];
    +                     }
    +                     else
    +                     {
    +                        /* Composite with background color:
    +                         * component =
    +                         *    alpha * component + (1 - alpha) * background
    +                         */
    +                        png_byte v, w;
    +
    +                        v = png_ptr->gamma_to_1[palette[i].red];
    +                        png_composite(w, v,
    +                            png_ptr->trans_alpha[i], back_1.red);
    +                        palette[i].red = png_ptr->gamma_from_1[w];
    +
    +                        v = png_ptr->gamma_to_1[palette[i].green];
    +                        png_composite(w, v,
    +                            png_ptr->trans_alpha[i], back_1.green);
    +                        palette[i].green = png_ptr->gamma_from_1[w];
    +
    +                        v = png_ptr->gamma_to_1[palette[i].blue];
    +                        png_composite(w, v,
    +                            png_ptr->trans_alpha[i], back_1.blue);
    +                        palette[i].blue = png_ptr->gamma_from_1[w];
    +                     }
                       }
                    }
                    else
    @@ -5032,13 +5077,8 @@ png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)
     
     #ifdef PNG_READ_QUANTIZE_SUPPORTED
        if ((png_ptr->transformations & PNG_QUANTIZE) != 0)
    -   {
           png_do_quantize(row_info, png_ptr->row_buf + 1,
               png_ptr->palette_lookup, png_ptr->quantize_index);
    -
    -      if (row_info->rowbytes == 0)
    -         png_error(png_ptr, "png_do_quantize returned rowbytes=0");
    -   }
     #endif /* READ_QUANTIZE */
     
     #ifdef PNG_READ_EXPAND_16_SUPPORTED
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
    index 6cf466d182a..07d53cb2c76 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
    @@ -29,7 +29,7 @@
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2024 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -2441,10 +2441,6 @@ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
        }
     #endif
     
    -   /* TODO: this doesn't work and shouldn't be necessary. */
    -   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
    -      png_ptr->mode |= PNG_AFTER_IDAT;
    -
        buffer = png_read_buffer(png_ptr, length+1);
     
        if (buffer == NULL)
    @@ -2515,10 +2511,6 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
        }
     #endif
     
    -   /* TODO: should not be necessary. */
    -   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
    -      png_ptr->mode |= PNG_AFTER_IDAT;
    -
        /* Note, "length" is sufficient here; we won't be adding
         * a null terminator later.  The limit check in png_handle_chunk should be
         * sufficient.
    @@ -2635,10 +2627,6 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
        }
     #endif
     
    -   /* TODO: should not be necessary. */
    -   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
    -      png_ptr->mode |= PNG_AFTER_IDAT;
    -
        buffer = png_read_buffer(png_ptr, length+1);
     
        if (buffer == NULL)
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
    index 1bfd292bd46..0b2844f1864 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
    @@ -329,17 +329,14 @@ png_set_mDCV(png_const_structrp png_ptr, png_inforp info_ptr,
         double maxDL, double minDL)
     {
        png_set_mDCV_fixed(png_ptr, info_ptr,
    -      /* The ITU approach is to scale by 50,000, not 100,000 so just divide
    -       * the input values by 2 and use png_fixed:
    -       */
    -      png_fixed(png_ptr, white_x / 2, "png_set_mDCV(white(x))"),
    -      png_fixed(png_ptr, white_y / 2, "png_set_mDCV(white(y))"),
    -      png_fixed(png_ptr, red_x / 2, "png_set_mDCV(red(x))"),
    -      png_fixed(png_ptr, red_y / 2, "png_set_mDCV(red(y))"),
    -      png_fixed(png_ptr, green_x / 2, "png_set_mDCV(green(x))"),
    -      png_fixed(png_ptr, green_y / 2, "png_set_mDCV(green(y))"),
    -      png_fixed(png_ptr, blue_x / 2, "png_set_mDCV(blue(x))"),
    -      png_fixed(png_ptr, blue_y / 2, "png_set_mDCV(blue(y))"),
    +      png_fixed(png_ptr, white_x, "png_set_mDCV(white(x))"),
    +      png_fixed(png_ptr, white_y, "png_set_mDCV(white(y))"),
    +      png_fixed(png_ptr, red_x, "png_set_mDCV(red(x))"),
    +      png_fixed(png_ptr, red_y, "png_set_mDCV(red(y))"),
    +      png_fixed(png_ptr, green_x, "png_set_mDCV(green(x))"),
    +      png_fixed(png_ptr, green_y, "png_set_mDCV(green(y))"),
    +      png_fixed(png_ptr, blue_x, "png_set_mDCV(blue(x))"),
    +      png_fixed(png_ptr, blue_y, "png_set_mDCV(blue(y))"),
           png_fixed_ITU(png_ptr, maxDL, "png_set_mDCV(maxDL)"),
           png_fixed_ITU(png_ptr, minDL, "png_set_mDCV(minDL)"));
     }
    diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
    index d6c446564d1..8edb4bc393a 100644
    --- a/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
    +++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
    @@ -22,14 +22,14 @@
      * questions.
      */
     
    -/* pngstruct.h - header file for PNG reference library
    +/* pngstruct.h - internal structures for libpng
      *
      * This file is available under and governed by the GNU General Public
      * License version 2 only, as published by the Free Software Foundation.
      * However, the following notice accompanied the original version of this
      * file and, per its terms, should not be removed:
      *
    - * Copyright (c) 2018-2022 Cosmin Truta
    + * Copyright (c) 2018-2025 Cosmin Truta
      * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
      * Copyright (c) 1996-1997 Andreas Dilger
      * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
    @@ -39,11 +39,9 @@
      * and license in png.h
      */
     
    -/* The structure that holds the information to read and write PNG files.
    - * The only people who need to care about what is inside of this are the
    - * people who will be modifying the library for their own special needs.
    - * It should NOT be accessed directly by an application.
    - */
    +#ifndef PNGPRIV_H
    +#  error This file must not be included by applications; please include 
    +#endif
     
     #ifndef PNGSTRUCT_H
     #define PNGSTRUCT_H
    @@ -406,7 +404,8 @@ struct png_struct_def
     
     /* New member added in libpng-1.6.36 */
     #if defined(PNG_READ_EXPAND_SUPPORTED) && \
    -    defined(PNG_ARM_NEON_IMPLEMENTATION)
    +    (defined(PNG_ARM_NEON_IMPLEMENTATION) || \
    +     defined(PNG_RISCV_RVV_IMPLEMENTATION))
        png_bytep riffled_palette; /* buffer for accelerated palette expansion */
     #endif
     
    @@ -435,7 +434,6 @@ struct png_struct_def
     
     #ifdef PNG_READ_QUANTIZE_SUPPORTED
     /* The following three members were added at version 1.0.14 and 1.2.4 */
    -   png_bytep quantize_sort;          /* working sort array */
        png_bytep index_to_palette;       /* where the original index currently is
                                             in the palette */
        png_bytep palette_to_index;       /* which original index points to this
    diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XKeysym.java b/src/java.desktop/unix/classes/sun/awt/X11/XKeysym.java
    index 2970305ce26..eab0898b47a 100644
    --- a/src/java.desktop/unix/classes/sun/awt/X11/XKeysym.java
    +++ b/src/java.desktop/unix/classes/sun/awt/X11/XKeysym.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2005, 2025, 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
    @@ -37,7 +37,9 @@
      */
     
     package sun.awt.X11;
    +
     import java.util.Hashtable;
    +import java.util.Map;
     import jdk.internal.misc.Unsafe;
     
     import sun.util.logging.PlatformLogger;
    @@ -68,7 +70,12 @@ public final class XKeysym {
         // for robot only it seems to me. After that, we can remove lookup table
         // from XWindow.c altogether.
         // Another use for reverse lookup: query keyboard state, for some keys.
    -    static Hashtable javaKeycode2KeysymHash = new Hashtable();
    +    private static final Map javaKeycode2KeysymHash = Map.of(
    +            java.awt.event.KeyEvent.VK_CAPS_LOCK, XKeySymConstants.XK_Caps_Lock,
    +            java.awt.event.KeyEvent.VK_NUM_LOCK, XKeySymConstants.XK_Num_Lock,
    +            java.awt.event.KeyEvent.VK_SCROLL_LOCK, XKeySymConstants.XK_Scroll_Lock,
    +            java.awt.event.KeyEvent.VK_KANA_LOCK, XKeySymConstants.XK_Kana_Lock
    +    );
         static long keysym_lowercase = unsafe.allocateMemory(Native.getLongSize());
         static long keysym_uppercase = unsafe.allocateMemory(Native.getLongSize());
         static Keysym2JavaKeycode kanaLock = new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_KANA_LOCK,
    @@ -289,9 +296,8 @@ public final class XKeysym {
             Keysym2JavaKeycode jkc = getJavaKeycode( keysym );
             return jkc == null ? java.awt.event.KeyEvent.VK_UNDEFINED : jkc.getJavaKeycode();
         }
    -    static long javaKeycode2Keysym( int jkey ) {
    -        Long ks = javaKeycode2KeysymHash.get( jkey );
    -        return  (ks == null ? 0 : ks.longValue());
    +    static long javaKeycode2Keysym(int jkey) {
    +        return javaKeycode2KeysymHash.getOrDefault(jkey, 0L);
         }
         /**
             Return keysym derived from a keycode and modifiers.
    @@ -1716,14 +1722,6 @@ public final class XKeysym {
             keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.hpXK_mute_asciitilde),     new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_DEAD_TILDE, java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
     
             keysym2JavaKeycodeHash.put( Long.valueOf(XConstants.NoSymbol),     new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_UNDEFINED, java.awt.event.KeyEvent.KEY_LOCATION_UNKNOWN));
    -
    -        /* Reverse search of keysym by keycode. */
    -
    -        /* Add keyboard locking codes. */
    -        javaKeycode2KeysymHash.put( java.awt.event.KeyEvent.VK_CAPS_LOCK, XKeySymConstants.XK_Caps_Lock);
    -        javaKeycode2KeysymHash.put( java.awt.event.KeyEvent.VK_NUM_LOCK, XKeySymConstants.XK_Num_Lock);
    -        javaKeycode2KeysymHash.put( java.awt.event.KeyEvent.VK_SCROLL_LOCK, XKeySymConstants.XK_Scroll_Lock);
    -        javaKeycode2KeysymHash.put( java.awt.event.KeyEvent.VK_KANA_LOCK, XKeySymConstants.XK_Kana_Lock);
         }
     
     }
    diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java
    index eab0817af23..78cd4a7e57d 100644
    --- a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java
    +++ b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java
    @@ -138,8 +138,6 @@ import sun.awt.X11GraphicsDevice;
     import sun.awt.X11GraphicsEnvironment;
     import sun.awt.XSettings;
     import sun.awt.datatransfer.DataTransferer;
    -import sun.awt.screencast.ScreencastHelper;
    -import sun.awt.screencast.XdgDesktopPortal;
     import sun.awt.util.PerformanceLogger;
     import sun.awt.util.ThreadGroupUtils;
     import sun.font.FontConfigManager;
    @@ -1523,21 +1521,16 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
             awtLock();
             try {
                 if (numberOfButtons == 0) {
    -                if (XdgDesktopPortal.isRemoteDesktop()
    -                        && ScreencastHelper.isAvailable()) {
    +                numberOfButtons = getNumberOfButtonsImpl();
    +                numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons;
    +                //4th and 5th buttons are for wheel and shouldn't be reported as buttons.
    +                //If we have more than 3 physical buttons and a wheel, we report N-2 buttons.
    +                //If we have 3 physical buttons and a wheel, we report 3 buttons.
    +                //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively.
    +                if (numberOfButtons >= 5) {
    +                    numberOfButtons -= 2;
    +                } else if (numberOfButtons == 4 || numberOfButtons == 5) {
                         numberOfButtons = 3;
    -                } else {
    -                    numberOfButtons = getNumberOfButtonsImpl();
    -                    numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons;
    -                    //4th and 5th buttons are for wheel and shouldn't be reported as buttons.
    -                    //If we have more than 3 physical buttons and a wheel, we report N-2 buttons.
    -                    //If we have 3 physical buttons and a wheel, we report 3 buttons.
    -                    //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively.
    -                    if (numberOfButtons >= 5) {
    -                        numberOfButtons -= 2;
    -                    } else if (numberOfButtons == 4 || numberOfButtons == 5) {
    -                        numberOfButtons = 3;
    -                    }
                     }
                 }
                 //Assume don't have to re-query the number again and again.
    diff --git a/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java b/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java
    index 33af39810d5..a8f7cd41a0e 100644
    --- a/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java
    +++ b/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java
    @@ -63,9 +63,11 @@ public final class ScreencastHelper {
         private static final int DELAY_BEFORE_SESSION_CLOSE = 2000;
     
         private static volatile TimerTask timerTask = null;
    -    private static final Timer timerCloseSession
    -            = new Timer("auto-close screencast session", true);
     
    +    private static class TimerHolder {
    +        private static final Timer timerCloseSession =
    +                new Timer("auto-close screencast session", true);
    +    }
     
         private ScreencastHelper() {}
     
    @@ -143,7 +145,7 @@ public final class ScreencastHelper {
                 }
             };
     
    -        timerCloseSession.schedule(timerTask, DELAY_BEFORE_SESSION_CLOSE);
    +        TimerHolder.timerCloseSession.schedule(timerTask, DELAY_BEFORE_SESSION_CLOSE);
         }
     
         public static synchronized void getRGBPixels(
    diff --git a/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java b/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java
    index 9db64725048..09dc84e74d0 100644
    --- a/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java
    +++ b/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java
    @@ -238,6 +238,7 @@ final class TokenStorage {
         }
     
         private static WatchService watchService;
    +    private static volatile boolean isWatcherThreadStarted = false;
     
         private static void setupWatch() {
             try {
    @@ -257,10 +258,6 @@ final class TokenStorage {
                             "file watch %s\n", e);
                 }
             }
    -
    -        if (watchService != null) {
    -            new WatcherThread(watchService).start();
    -        }
         }
     
         // called from native
    @@ -337,7 +334,27 @@ final class TokenStorage {
             return true;
         }
     
    +    private static void startWatcherThreadIfNeeded() {
    +        if (!isWatcherThreadStarted) {
    +            // not sure if the double-checked locking is actually needed here
    +            // the getTokens is only called from ScreencastHelper#getRGBPixels
    +            // and ScreencastHelper#remoteDesktop* methods (which are synchronized),
    +            // but it may change later.
    +            synchronized (TokenStorage.class) {
    +                if (!isWatcherThreadStarted) {
    +                    readTokens(PROPS_PATH);
    +                    if (watchService != null) {
    +                        new WatcherThread(watchService).start();
    +                    }
    +                    isWatcherThreadStarted = true;
    +                }
    +            }
    +        }
    +    }
    +
         static Set getTokens(List affectedScreenBounds) {
    +        startWatcherThreadIfNeeded();
    +
             // We need an ordered set to store tokens
             // with exact matches at the beginning.
             LinkedHashSet result = new LinkedHashSet<>();
    diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c
    index e5b2dfa6db9..03dba969e8d 100644
    --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c
    +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c
    @@ -42,7 +42,6 @@
     #include "debug_assert.h"
     
     static void *gtk3_libhandle = NULL;
    -static void *gthread_libhandle = NULL;
     
     static void transform_detail_string (const gchar *detail,
                                          GtkStyleContext *context);
    @@ -79,15 +78,6 @@ static void* dl_symbol(const char* name)
         return result;
     }
     
    -static void* dl_symbol_gthread(const char* name)
    -{
    -    void* result = dlsym(gthread_libhandle, name);
    -    if (!result)
    -        longjmp(j, NO_SYMBOL_EXCEPTION);
    -
    -    return result;
    -}
    -
     gboolean gtk3_check(const char* lib_name, gboolean load)
     {
         if (gtk3_libhandle != NULL) {
    @@ -264,13 +254,6 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)
             return FALSE;
         }
     
    -    gthread_libhandle = dlopen(GTHREAD_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL);
    -    if (gthread_libhandle == NULL) {
    -        gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL);
    -        if (gthread_libhandle == NULL)
    -            return FALSE;
    -    }
    -
         if (setjmp(j) == 0)
         {
             fp_gtk_check_version = dl_symbol("gtk_check_version");
    @@ -634,9 +617,6 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)
             dlclose(gtk3_libhandle);
             gtk3_libhandle = NULL;
     
    -        dlclose(gthread_libhandle);
    -        gthread_libhandle = NULL;
    -
             return NULL;
         }
     
    @@ -735,7 +715,6 @@ static int gtk3_unload()
     
         dlerror();
         dlclose(gtk3_libhandle);
    -    dlclose(gthread_libhandle);
         if ((gtk3_error = dlerror()) != NULL)
         {
             return FALSE;
    diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h
    index 11ec245ce8b..39be6a735d7 100644
    --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h
    +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h
    @@ -38,9 +38,6 @@
     #define TRUE            (!FALSE)
     #endif
     
    -#define GTHREAD_LIB_VERSIONED VERSIONED_JNI_LIB_NAME("gthread-2.0", "0")
    -#define GTHREAD_LIB JNI_LIB_NAME("gthread-2.0")
    -
     #define _G_TYPE_CIC(ip, gt, ct)       ((ct*) ip)
     #define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type)  \
                                         (_G_TYPE_CIC ((instance), (g_type), c_type))
    @@ -850,9 +847,6 @@ typedef struct GtkApi {
     gboolean gtk_load(JNIEnv *env, GtkVersion version, gboolean verbose);
     gboolean gtk_check_version(GtkVersion version);
     
    -typedef struct _GThreadFunctions GThreadFunctions;
    -static gboolean (*fp_g_thread_get_initialized)(void);
    -static void (*fp_g_thread_init)(GThreadFunctions *vtable);
     static void (*fp_gdk_threads_init)(void);
     static void (*fp_gdk_threads_enter)(void);
     static void (*fp_gdk_threads_leave)(void);
    diff --git a/src/java.management/share/classes/java/lang/management/MemoryMXBean.java b/src/java.management/share/classes/java/lang/management/MemoryMXBean.java
    index 2c982e1ce9c..247868d3d99 100644
    --- a/src/java.management/share/classes/java/lang/management/MemoryMXBean.java
    +++ b/src/java.management/share/classes/java/lang/management/MemoryMXBean.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2003, 2025, 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
    @@ -267,6 +267,42 @@ public interface MemoryMXBean extends PlatformManagedObject {
          */
         public MemoryUsage getNonHeapMemoryUsage();
     
    +    /**
    +     * Returns the approximate accumulated time, in nanoseconds,
    +     * spent in garbage collection (GC).
    +     *
    +     * 

    The time spent in spent in GC is the CPU time used by + * all GC activity, including any overhead, which means the + * result may be non-zero even if no GC has occurred. + * + * This method returns {@code -1} if the platform does + * not support this operation or the information is not + * available. + * + * @apiNote + * May be used in conjunction with {@code jdk.management/com.sun.management.OperatingSystemMXBean#getProcessCpuTime()} + * for calculating the GC's usage of CPU time as a whole. + * + * @implNote The specifics on what constitutes the time spent + * in GC are highly implementation dependent. In the HotSpot + * Virtual Machine, this time includes relevant + * implementation-specific details such as driver threads, + * workers, VM Operations and string deduplication (if + * enabled). Driver threads may be created by a GC to + * orchestrate its work. The return value can be -1 if called + * when measurement is not possible, such as during shutdown. + * + * @implSpec The default implementation returns {@code -1}. + * + * @return the total accumulated CPU time for GC in + * nanoseconds, or {@code -1}. + * + * @since 26 + */ + default public long getTotalGcCpuTime() { + return -1; + } + /** * Tests if verbose output for the memory system is enabled. * @@ -302,5 +338,4 @@ public interface MemoryMXBean extends PlatformManagedObject { * @see java.lang.System#gc() */ public void gc(); - } diff --git a/src/java.management/share/classes/sun/management/MemoryImpl.java b/src/java.management/share/classes/sun/management/MemoryImpl.java index e1f68ce3711..3e27ba2e5bb 100644 --- a/src/java.management/share/classes/sun/management/MemoryImpl.java +++ b/src/java.management/share/classes/sun/management/MemoryImpl.java @@ -67,6 +67,10 @@ class MemoryImpl extends NotificationEmitterSupport Runtime.getRuntime().gc(); } + public long getTotalGcCpuTime() { + return jvm.getTotalGcCpuTime(); + } + // Need to make a VM call to get coherent value public MemoryUsage getHeapMemoryUsage() { return getMemoryUsage0(true); diff --git a/src/java.management/share/classes/sun/management/ThreadImpl.java b/src/java.management/share/classes/sun/management/ThreadImpl.java index be54ced066d..a246e01dd63 100644 --- a/src/java.management/share/classes/sun/management/ThreadImpl.java +++ b/src/java.management/share/classes/sun/management/ThreadImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -308,7 +308,7 @@ public class ThreadImpl implements ThreadMXBean { long id = ids[0]; Thread thread = Thread.currentThread(); if (id == thread.threadId()) { - times[0] = thread.isVirtual() ? -1L : getThreadTotalCpuTime0(0); + times[0] = thread.isVirtual() ? -1L : getThreadUserCpuTime0(0); } else { times[0] = getThreadUserCpuTime0(id); } diff --git a/src/java.management/share/classes/sun/management/VMManagement.java b/src/java.management/share/classes/sun/management/VMManagement.java index f4445f0225a..3e227225ccd 100644 --- a/src/java.management/share/classes/sun/management/VMManagement.java +++ b/src/java.management/share/classes/sun/management/VMManagement.java @@ -55,6 +55,7 @@ public interface VMManagement { public boolean getVerboseClass(); // Memory Subsystem + public long getTotalGcCpuTime(); public boolean getVerboseGC(); // Runtime Subsystem diff --git a/src/java.management/share/classes/sun/management/VMManagementImpl.java b/src/java.management/share/classes/sun/management/VMManagementImpl.java index 041f09547d2..b8c7a2921d4 100644 --- a/src/java.management/share/classes/sun/management/VMManagementImpl.java +++ b/src/java.management/share/classes/sun/management/VMManagementImpl.java @@ -128,6 +128,7 @@ class VMManagementImpl implements VMManagement { public native boolean getVerboseClass(); // Memory Subsystem + public native long getTotalGcCpuTime(); public native boolean getVerboseGC(); // Runtime Subsystem diff --git a/src/java.management/share/native/libmanagement/VMManagementImpl.c b/src/java.management/share/native/libmanagement/VMManagementImpl.c index f1a566676dc..d5141c71ee7 100644 --- a/src/java.management/share/native/libmanagement/VMManagementImpl.c +++ b/src/java.management/share/native/libmanagement/VMManagementImpl.c @@ -121,6 +121,13 @@ Java_sun_management_VMManagementImpl_getUnloadedClassCount return count; } +JNIEXPORT jlong JNICALL +Java_sun_management_VMManagementImpl_getTotalGcCpuTime + (JNIEnv *env, jobject dummy) +{ + return jmm_interface->GetLongAttribute(env, NULL, JMM_TOTAL_GC_CPU_TIME); +} + JNIEXPORT jboolean JNICALL Java_sun_management_VMManagementImpl_getVerboseGC (JNIEnv *env, jobject dummy) diff --git a/src/java.net.http/share/classes/java/net/http/HttpClient.java b/src/java.net.http/share/classes/java/net/http/HttpClient.java index a7a2171857d..9ecb048342b 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpClient.java +++ b/src/java.net.http/share/classes/java/net/http/HttpClient.java @@ -312,10 +312,22 @@ public abstract class HttpClient implements AutoCloseable { * need to be established, for example if a connection can be reused * from a previous request, then this timeout duration has no effect. * + * @implSpec + * A connection timeout applies to the entire connection phase, from the + * moment a connection is requested until it is established. + * Implementations are recommended to ensure that the connection timeout + * covers any SSL/TLS handshakes. + * + * @implNote + * The built-in JDK implementation of the connection timeout covers any + * SSL/TLS handshakes. + * * @param duration the duration to allow the underlying connection to be * established * @return this builder * @throws IllegalArgumentException if the duration is non-positive + * @see HttpRequest.Builder#timeout(Duration) Configuring timeout for + * request execution */ public Builder connectTimeout(Duration duration); diff --git a/src/java.net.http/share/classes/java/net/http/HttpRequest.java b/src/java.net.http/share/classes/java/net/http/HttpRequest.java index c56328ba4b4..741573e06b3 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpRequest.java +++ b/src/java.net.http/share/classes/java/net/http/HttpRequest.java @@ -258,12 +258,28 @@ public abstract class HttpRequest { * {@link HttpClient#sendAsync(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync} * completes exceptionally with an {@code HttpTimeoutException}. The effect - * of not setting a timeout is the same as setting an infinite Duration, - * i.e. block forever. + * of not setting a timeout is the same as setting an infinite + * {@code Duration}, i.e., block forever. + * + * @implSpec + * A timeout applies to the duration measured from the instant the + * request execution starts to, at least, the instant an + * {@link HttpResponse} is constructed. The elapsed time includes + * obtaining a connection for transport and retrieving the response + * headers. + * + * @implNote + * The JDK built-in implementation applies timeout over the duration + * measured from the instant the request execution starts to the + * instant the response body is consumed, if present. This is + * implemented by stopping the timer after the response body subscriber + * completion. * * @param duration the timeout duration * @return this builder * @throws IllegalArgumentException if the duration is non-positive + * @see HttpClient.Builder#connectTimeout(Duration) Configuring + * timeout for connection establishment */ public abstract Builder timeout(Duration duration); diff --git a/src/java.net.http/share/classes/java/net/http/WebSocket.java b/src/java.net.http/share/classes/java/net/http/WebSocket.java index 313847cf449..84fc8472eef 100644 --- a/src/java.net.http/share/classes/java/net/http/WebSocket.java +++ b/src/java.net.http/share/classes/java/net/http/WebSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -144,6 +144,16 @@ public interface WebSocket { * {@link HttpTimeoutException}. If this method is not invoked then the * infinite timeout is assumed. * + * @implSpec + * A connection timeout applies to the entire connection phase, from the + * moment a connection is requested until it is established. + * Implementations are recommended to ensure that the connection timeout + * covers any WebSocket and SSL/TLS handshakes. + * + * @implNote + * The built-in JDK implementation of the connection timeout covers any + * WebSocket and SSL/TLS handshakes. + * * @param timeout * the timeout, non-{@linkplain Duration#isNegative() negative}, * non-{@linkplain Duration#ZERO ZERO} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java index 1d8cb013295..e1725aa92d5 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java @@ -205,32 +205,38 @@ final class ConnectionPool { // it's possible that cleanup may have been called. HttpConnection toClose = null; + boolean stopping = false; stateLock.lock(); try { if (cleanup.isDone()) { return; - } else if (stopped) { - conn.close(); - return; - } - if (MAX_POOL_SIZE > 0 && expiryList.size() >= MAX_POOL_SIZE) { - toClose = expiryList.removeOldest(); - if (toClose != null) removeFromPool(toClose); - } - if (conn instanceof PlainHttpConnection) { - putConnection(conn, plainPool); + } else if (stopping = stopped) { + toClose = conn; } else { - assert conn.isSecure(); - putConnection(conn, sslPool); + if (MAX_POOL_SIZE > 0 && expiryList.size() >= MAX_POOL_SIZE) { + toClose = expiryList.removeOldest(); + if (toClose != null) removeFromPool(toClose); + } + if (conn instanceof PlainHttpConnection) { + putConnection(conn, plainPool); + } else { + assert conn.isSecure(); + putConnection(conn, sslPool); + } + expiryList.add(conn, now, keepAlive); } - expiryList.add(conn, now, keepAlive); } finally { stateLock.unlock(); } if (toClose != null) { if (debug.on()) { - debug.log("Maximum pool size reached: removing oldest connection %s", - toClose.dbgString()); + if (stopping) { + debug.log("Stopping: close connection %s", + toClose.dbgString()); + } else { + debug.log("Maximum pool size reached: removing oldest connection %s", + toClose.dbgString()); + } } close(toClose); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java index 897845345ce..0567a1c6d6d 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java @@ -32,7 +32,6 @@ import java.net.http.HttpHeaders; import java.time.Duration; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -741,12 +740,10 @@ final class Exchange { if (s == null) { // s can be null if an exception occurred // asynchronously while sending the preface. - Throwable t = c.getRecordedCause(); + final Http2TerminationCause tc = c.getTerminationCause(); IOException ioe; - if (t != null) { - if (!cached) - c.close(); - ioe = new IOException("Can't get stream 1: " + t, t); + if (tc != null) { + ioe = new IOException("Can't get stream 1", tc.getCloseCause()); } else { ioe = new IOException("Can't get stream 1"); } @@ -769,7 +766,7 @@ final class Exchange { t = failed.get(); } // Check whether the HTTP/1.1 was cancelled. - if (t == null) t = e.getCancelCause(); + if (t == null) t = e.getCancelCause(); // if HTTP/1.1 exchange was timed out, or the request // was cancelled don't try to go further. if (t instanceof HttpTimeoutException || multi.requestCancelled()) { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java index 74600e78557..c1ed01ff07a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java @@ -581,6 +581,18 @@ abstract class ExchangeImpl { // Needed for HTTP/2 to subscribe a dummy subscriber and close the stream } + /** + * {@return {@code true}, if it is allowed to cancel the request timer on + * response body subscriber termination; {@code false}, otherwise} + * + * @param webSocket indicates if the associated request is a WebSocket handshake + * @param statusCode the status code of the associated response + */ + static boolean cancelTimerOnResponseBodySubscriberTermination( + boolean webSocket, int statusCode) { + return webSocket || statusCode < 100 || statusCode >= 200; + } + /* The following methods have separate HTTP/1.1 and HTTP/2 implementations */ abstract CompletableFuture> sendHeadersAsync(); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java index 02ce63b6314..72a47eca42c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java @@ -206,8 +206,15 @@ class Http1Exchange extends ExchangeImpl { */ static final class Http1ResponseBodySubscriber extends HttpBodySubscriberWrapper { final Http1Exchange exchange; - Http1ResponseBodySubscriber(BodySubscriber userSubscriber, Http1Exchange exchange) { + + private final boolean cancelTimerOnTermination; + + Http1ResponseBodySubscriber( + BodySubscriber userSubscriber, + boolean cancelTimerOnTermination, + Http1Exchange exchange) { super(userSubscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; this.exchange = exchange; } @@ -220,6 +227,14 @@ class Http1Exchange extends ExchangeImpl { protected void unregister() { exchange.unregisterResponseSubscriber(this); } + + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.exchange.multi.cancelTimer(); + } + } + } @Override @@ -459,9 +474,10 @@ class Http1Exchange extends ExchangeImpl { @Override Http1ResponseBodySubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { BodySubscriber subscriber = handler.apply(response); - Http1ResponseBodySubscriber bs = - new Http1ResponseBodySubscriber(subscriber, this); - return bs; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http1ResponseBodySubscriber<>(subscriber, cancelTimerOnTermination, this); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java index cc8a2a7142b..6121a0c1673 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package jdk.internal.net.http; -import java.io.EOFException; import java.io.IOException; import java.io.UncheckedIOException; import java.util.Base64; @@ -234,11 +233,8 @@ class Http2ClientImpl { } } - private EOFException STOPPED; void stop() { if (debug.on()) debug.log("stopping"); - STOPPED = new EOFException("HTTP/2 client stopped"); - STOPPED.setStackTrace(new StackTraceElement[0]); connectionPoolLock.lock(); try { stopping = true; @@ -253,10 +249,7 @@ class Http2ClientImpl { private boolean close(Http2Connection h2c) { // close all streams try { h2c.closeAllStreams(); } catch (Throwable t) {} - // send GOAWAY try { h2c.close(); } catch (Throwable t) {} - // attempt graceful shutdown - try { h2c.shutdown(STOPPED); } catch (Throwable t) {} // double check and close any new streams try { h2c.closeAllStreams(); } catch (Throwable t) {} // Allows for use of removeIf in stop() diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java index 63889fa6af2..94b8505da47 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java @@ -25,21 +25,20 @@ package jdk.internal.net.http; +import java.io.Closeable; import java.io.EOFException; import java.io.IOException; import java.io.UncheckedIOException; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; import java.net.InetSocketAddress; import java.net.ProtocolException; import java.net.http.HttpClient; import java.net.http.HttpClient.Version; import java.net.http.HttpHeaders; import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.net.http.HttpConnectTimeoutException; import java.time.Duration; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -49,6 +48,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; @@ -56,6 +56,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; import java.util.function.Supplier; + import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; @@ -130,7 +131,7 @@ import static jdk.internal.net.http.frame.SettingsFrame.MAX_HEADER_LIST_SIZE; * and incoming stream creation (Server push). Incoming frames destined for a * stream are provided by calling Stream.incoming(). */ -class Http2Connection { +class Http2Connection implements Closeable { final Logger debug = Utils.getDebugLogger(this::dbgString); static final Logger DEBUG_LOGGER = @@ -143,6 +144,8 @@ class Http2Connection { private static final int MAX_SERVER_STREAM_ID = Integer.MAX_VALUE - 1; // 2147483646 // may be null; must be accessed/updated with the stateLock held private IdleConnectionTimeoutEvent idleConnectionTimeoutEvent; + private final AtomicBoolean goAwaySent = new AtomicBoolean(); + private final AtomicBoolean goAwayRecvd = new AtomicBoolean(); /** * Flag set when no more streams to be opened on this connection. @@ -215,7 +218,7 @@ class Http2Connection { } /** - * {@link #shutdown(Throwable) Shuts down} the connection, unless this event is + * {@link #close(Http2TerminationCause) Closes} the connection, unless this event is * {@link #cancelled} */ @Override @@ -228,26 +231,20 @@ class Http2Connection { try { if (cancelled) { if (debug.on()) { - debug.log("Not initiating idle connection shutdown"); - } - return; - } - if (!markIdleShutdownInitiated()) { - if (debug.on()) { - debug.log("Unexpected state %s, skipping idle connection shutdown", - describeClosedState(closedState)); + debug.log("Idle timeout event already cancelled, not initiating idle connection close"); } return; } + // the connection has been idle long enough, we now + // mark a state indicating that the connection is chosen + // for idle termination and should not be handed out (from the pool) + // for newer requests. + connTerminator.markForIdleTermination(); } finally { stateLock.unlock(); } - if (debug.on()) { - debug.log("Initiating shutdown of HTTP connection which is idle for too long"); - } - HttpConnectTimeoutException hte = new HttpConnectTimeoutException( - "HTTP connection idle, no active streams. Shutting down."); - shutdown(hte); + // terminate the connection due to being idle long enough + connTerminator.idleTimedOut(); } /** @@ -256,7 +253,7 @@ class Http2Connection { void cancel() { assert stateLock.isHeldByCurrentThread() : "Current thread doesn't hold " + stateLock; // mark as cancelled to prevent potentially already triggered event from actually - // doing the shutdown + // doing the close this.cancelled = true; // cancel the timer to prevent the event from being triggered (if it hasn't already) client().cancelTimer(this); @@ -376,16 +373,7 @@ class Http2Connection { } - private static final int HALF_CLOSED_LOCAL = 1; - private static final int HALF_CLOSED_REMOTE = 2; - private static final int SHUTDOWN_REQUESTED = 4; - // state when idle connection management initiates a shutdown of the connection, after - // which the connection will go into SHUTDOWN_REQUESTED state - private static final int IDLE_SHUTDOWN_INITIATED = 8; private final ReentrantLock stateLock = new ReentrantLock(); - private volatile int closedState; - - //------------------------------------- final HttpConnection connection; private final Http2ClientImpl client2; private final ConcurrentHashMap> streams = new ConcurrentHashMap<>(); @@ -403,7 +391,9 @@ class Http2Connection { private final Decoder hpackIn; final SettingsFrame clientSettings; private volatile SettingsFrame serverSettings; + private record PushContinuationState(PushPromiseDecoder pushContDecoder, PushPromiseFrame pushContFrame) {} + private volatile PushContinuationState pushContinuationState; private final String key; // for HttpClientImpl.connections map private final FramesDecoder framesDecoder; @@ -418,7 +408,7 @@ class Http2Connection { private final FramesController framesController = new FramesController(); private final Http2TubeSubscriber subscriber; final ConnectionWindowUpdateSender windowUpdater; - private final AtomicReference cause = new AtomicReference<>(); + private final Terminator connTerminator = new Terminator(); private volatile Supplier initial; private volatile Stream initialStream; @@ -640,35 +630,31 @@ class Http2Connection { } void abandonStream() { - boolean shouldClose = false; stateLock.lock(); try { long reserved = --numReservedClientStreams; assert reserved >= 0; - if (finalStream && reserved == 0 && streams.isEmpty()) { - shouldClose = true; - } } catch (Throwable t) { - shutdown(t); // in case the assert fires... + close(Http2TerminationCause.forException(t)); // in case the assert fires... } finally { stateLock.unlock(); } - // We should close the connection here if - // it's not pooled. If it's not pooled it will - // be marked final stream, reserved will be 0 - // after decrementing it by one, and there should - // be no active request-response streams. - if (shouldClose) { - shutdown(new IOException("HTTP/2 connection abandoned")); + // if the connection is eligible to be closed, we close it here + if (shouldClose()) { + close(Http2TerminationCause.noErrorTermination()); } - } - boolean shouldClose() { + /* + * return true if the connection is marked as "final stream" and there + * are no active streams on that connection and the connection isn't + * reserved for a new stream. + */ + final boolean shouldClose() { stateLock.lock(); try { - return finalStream() && streams.isEmpty(); + return finalStream() && streams.isEmpty() && numReservedClientStreams == 0; } finally { stateLock.unlock(); } @@ -840,22 +826,8 @@ class Http2Connection { return clientSettings.getParameter(MAX_CONCURRENT_STREAMS); } - void close() { - if (markHalfClosedLocal()) { - // we send a GOAWAY frame only if the remote side hasn't already indicated - // the intention to close the connection by previously sending a GOAWAY of its own - if (connection.channel().isOpen() && !isMarked(closedState, HALF_CLOSED_REMOTE)) { - Log.logTrace("Closing HTTP/2 connection: to {0}", connection.address()); - GoAwayFrame f = new GoAwayFrame(0, - ErrorFrame.NO_ERROR, - "Requested by user".getBytes(UTF_8)); - // TODO: set last stream. For now zero ok. - sendFrame(f); - } - } - } - long count; + final void asyncReceive(ByteBuffer buffer) { // We don't need to read anything and // we don't want to send anything back to the server @@ -904,44 +876,26 @@ class Http2Connection { } catch (Throwable e) { String msg = Utils.stackTrace(e); Log.logTrace(msg); - shutdown(e); + close(Http2TerminationCause.forException(e)); } } - Throwable getRecordedCause() { - return cause.get(); + /** + * Closes the connection normally (with a NO_ERROR termination cause), if not already closed. + */ + @Override + public final void close() { + close(Http2TerminationCause.noErrorTermination()); } - void shutdown(Throwable t) { - int state = closedState; - if (debug.on()) debug.log(() -> "Shutting down h2c (state="+describeClosedState(state)+"): " + t); - stateLock.lock(); - try { - if (!markShutdownRequested()) return; - cause.compareAndSet(null, t); - } finally { - stateLock.unlock(); - } - - if (Log.errors()) { - if (t!= null && (!(t instanceof EOFException) || isActive())) { - Log.logError(t); - } else if (t != null) { - Log.logError("Shutting down connection: {0}", t.getMessage()); - } else { - Log.logError("Shutting down connection"); - } - } - client2.removeFromPool(this); - subscriber.stop(cause.get()); - for (Stream s : streams.values()) { - try { - s.connectionClosing(t); - } catch (Throwable e) { - Log.logError("Failed to close stream {0}: {1}", s.streamid, e); - } - } - connection.close(cause.get()); + /** + * Closes the connection with the given termination cause, if not already closed. + * + * @param tc the termination cause. cannot be null. + */ + final void close(final Http2TerminationCause tc) { + Objects.requireNonNull(tc, "termination cause cannot be null"); + this.connTerminator.terminate(tc); } /** @@ -981,15 +935,14 @@ class Http2Connection { } else { if (frame instanceof SettingsFrame) { // The stream identifier for a SETTINGS frame MUST be zero - framesDecoder.close( + protocolError(ErrorFrame.PROTOCOL_ERROR, "The stream identifier for a SETTINGS frame MUST be zero"); - protocolError(GoAwayFrame.PROTOCOL_ERROR); return; } if (frame instanceof PushPromiseFrame && !serverPushEnabled()) { String protocolError = "received a PUSH_PROMISE when SETTINGS_ENABLE_PUSH is 0"; - protocolError(ResetFrame.PROTOCOL_ERROR, protocolError); + protocolError(ErrorFrame.PROTOCOL_ERROR, protocolError); return; } @@ -1144,7 +1097,9 @@ class Http2Connection { // Otherwise, if the frame is dropped after having been added to the // inputQ, releaseUnconsumed above should be called. final void dropDataFrame(DataFrame df) { - if (isMarked(closedState, SHUTDOWN_REQUESTED)) return; + if (!isOpen()) { + return; + } if (debug.on()) { debug.log("Dropping data frame for stream %d (%d payload bytes)", df.streamid(), df.payloadLength()); @@ -1154,7 +1109,9 @@ class Http2Connection { final void ensureWindowUpdated(DataFrame df) { try { - if (isMarked(closedState, SHUTDOWN_REQUESTED)) return; + if (!isOpen()) { + return; + } int length = df.payloadLength(); if (length > 0) { windowUpdater.update(length); @@ -1251,12 +1208,16 @@ class Http2Connection { case AltSvcFrame.TYPE -> processAltSvcFrame(0, (AltSvcFrame) frame, connection, connection.client()); - default -> protocolError(ErrorFrame.PROTOCOL_ERROR); + default -> protocolError(ErrorFrame.PROTOCOL_ERROR, "unknown frame: " + frame); } } - boolean isOpen() { - return !isMarkedForShutdown() && connection.channel().isOpen(); + /** + * Returns true if this connection hasn't been terminated and the underlying + * {@linkplain NetworkChannel#isOpen() channel is open}. false otherwise. + */ + final boolean isOpen() { + return this.connTerminator.terminationCause.get() == null && connection.channel().isOpen(); } void resetStream(int streamid, int code) { @@ -1295,6 +1256,7 @@ class Http2Connection { } } + private void decrementStreamsCount0(int streamid) { Stream s = streams.get(streamid); if (s == null || !s.deRegister()) @@ -1346,8 +1308,7 @@ class Http2Connection { // corresponding entry in the window controller. windowController.removeStream(streamid); } - if (finalStream() && streams.isEmpty()) { - // should be only 1 stream, but there might be more if server push + if (shouldClose()) { close(); } else { // Start timer if property present and not already created @@ -1372,9 +1333,7 @@ class Http2Connection { /** * Increments this connection's send Window by the amount in the given frame. */ - private void handleWindowUpdate(WindowUpdateFrame f) - throws IOException - { + private void handleWindowUpdate(WindowUpdateFrame f) { int amount = f.getUpdate(); if (amount <= 0) { // ## temporarily disable to workaround a bug in Jetty where it @@ -1383,37 +1342,19 @@ class Http2Connection { } else { boolean success = windowController.increaseConnectionWindow(amount); if (!success) { - protocolError(ErrorFrame.FLOW_CONTROL_ERROR); // overflow + protocolError(ErrorFrame.FLOW_CONTROL_ERROR, null); // overflow } } } - private void protocolError(int errorCode) - throws IOException - { - protocolError(errorCode, null); + private void protocolError(final int errorCode, final String msg) { + final Http2TerminationCause terminationCause = + Http2TerminationCause.forH2Error(errorCode, msg); + framesDecoder.close(terminationCause.getLogMsg()); + close(terminationCause); } - private void protocolError(int errorCode, String msg) - throws IOException - { - String protocolError = "protocol error" + (msg == null?"":(": " + msg)); - ProtocolException protocolException = - new ProtocolException(protocolError); - this.cause.compareAndSet(null, protocolException); - if (markHalfClosedLocal()) { - framesDecoder.close(protocolError); - subscriber.stop(protocolException); - if (debug.on()) debug.log("Sending GOAWAY due to " + protocolException); - GoAwayFrame frame = new GoAwayFrame(0, errorCode); - sendFrame(frame); - } - shutdown(protocolException); - } - - private void handleSettings(SettingsFrame frame) - throws IOException - { + private void handleSettings(SettingsFrame frame) { assert frame.streamid() == 0; if (!frame.getFlag(SettingsFrame.ACK)) { int newWindowSize = frame.getParameter(INITIAL_WINDOW_SIZE); @@ -1430,9 +1371,7 @@ class Http2Connection { } } - private void handlePing(PingFrame frame) - throws IOException - { + private void handlePing(PingFrame frame) { frame.setFlag(PingFrame.ACK); sendUnorderedFrame(frame); } @@ -1442,7 +1381,7 @@ class Http2Connection { assert lastProcessedStream >= 0 : "unexpected last stream id: " + lastProcessedStream + " in GOAWAY frame"; - markHalfClosedRemote(); + goAwayRecvd.set(true); setFinalStream(); // don't allow any new streams on this connection if (debug.on()) { debug.log("processing incoming GOAWAY with last processed stream id:%s in frame %s", @@ -1599,20 +1538,20 @@ class Http2Connection { // must be done with "stateLock" held to co-ordinate idle connection management stateLock.lock(); try { - cancelIdleShutdownEvent(); - // consider the reservation successful only if the connection's state hasn't moved - // to "being closed" - return isOpen(); + cancelIdleCloseEvent(); + // consider the reservation successful only if the connection is open and + // hasn't been chosen for idle termination + return !this.connTerminator.isMarkedForIdleTermination() && isOpen(); } finally { stateLock.unlock(); } } /** - * Cancels any event that might have been scheduled to shutdown this connection. Must be called + * Cancels any event that might have been scheduled to close this connection. Must be called * with the stateLock held. */ - private void cancelIdleShutdownEvent() { + private void cancelIdleCloseEvent() { assert stateLock.isHeldByCurrentThread() : "Current thread doesn't hold " + stateLock; if (idleConnectionTimeoutEvent == null) { return; @@ -1627,20 +1566,23 @@ class Http2Connection { // the stream is closed. stateLock.lock(); try { - if (!isMarkedForShutdown()) { + if (isOpen() && !this.connTerminator.isMarkedForIdleTermination()) { if (debug.on()) { debug.log("Opened stream %d", streamid); } client().streamReference(); streams.put(streamid, stream); - cancelIdleShutdownEvent(); + // don't consider the connection idle anymore + cancelIdleCloseEvent(); return; } } finally { stateLock.unlock(); } if (debug.on()) debug.log("connection closed: closing stream %d", stream); - stream.cancel(new IOException("Stream " + streamid + " cancelled", cause.get())); + final Http2TerminationCause terminationCause = getTerminationCause(); + assert terminationCause != null : "termination cause is null"; + stream.cancel(new IOException("Stream " + streamid + " cancelled", terminationCause.getCloseCause())); } /** @@ -1743,11 +1685,10 @@ class Http2Connection { int streamid = nextstreamid; Throwable cause = null; synchronized (this) { - if (isMarked(closedState, SHUTDOWN_REQUESTED)) { - cause = this.cause.get(); - if (cause == null) { - cause = new IOException("Connection closed"); - } + if (!isOpen()) { + final Http2TerminationCause terminationCause = getTerminationCause(); + assert terminationCause != null : "termination cause is null"; + cause = terminationCause.getCloseCause(); } } if (cause != null) { @@ -1762,7 +1703,7 @@ class Http2Connection { return stream; } else { stream.cancelImpl(new IOException("Request cancelled")); - if (finalStream() && streams.isEmpty()) { + if (shouldClose()) { close(); } return null; @@ -1795,14 +1736,12 @@ class Http2Connection { } publisher.signalEnqueued(); } catch (IOException e) { - if (!isMarked(closedState, SHUTDOWN_REQUESTED)) { - if (!client2.stopping()) { - Log.logError(e); - shutdown(e); - } else if (debug.on()) { - debug.log("Failed to send %s while stopping: %s", frame, e); - } + if (!client2.stopping()) { + Log.logError(e); + } else if (debug.on()) { + debug.log("Failed to send %s while stopping: %s", frame, e); } + close(Http2TerminationCause.forException(e)); } } @@ -1817,14 +1756,12 @@ class Http2Connection { publisher.enqueue(encodeFrame(frame)); publisher.signalEnqueued(); } catch (IOException e) { - if (!isMarked(closedState, SHUTDOWN_REQUESTED)) { - if (!client2.stopping()) { - Log.logError(e); - shutdown(e); - } else if (debug.on()) { - debug.log("Failed to send %s while stopping: %s", frame, e); - } + if (!client2.stopping()) { + Log.logError(e); + } else if (debug.on()) { + debug.log("Failed to send %s while stopping: %s", frame, e); } + close(Http2TerminationCause.forException(e)); } } @@ -1839,10 +1776,12 @@ class Http2Connection { publisher.enqueueUnordered(encodeFrame(frame)); publisher.signalEnqueued(); } catch (IOException e) { - if (!isMarked(closedState, SHUTDOWN_REQUESTED)) { + if (!client2.stopping()) { Log.logError(e); - shutdown(e); + } else if (debug.on()) { + debug.log("Failed to send %s while stopping: %s", frame, e); } + close(Http2TerminationCause.forException(e)); } } @@ -1868,6 +1807,7 @@ class Http2Connection { try { while (!queue.isEmpty() && !scheduler.isStopped()) { ByteBuffer buffer = queue.poll(); + assert buffer != null : "null buffer obtained from non-empty queue"; if (debug.on()) debug.log("sending %d to Http2Connection.asyncReceive", buffer.remaining()); @@ -1877,7 +1817,12 @@ class Http2Connection { errorRef.compareAndSet(null, t); } finally { Throwable x = errorRef.get(); - if (x != null) { + // if there was any error or if the TubeSubscriber completed normally, + // then close the connection + if (x != null || completed) { + // although the connection terminator stops the scheduler too, + // we don't want to wait that "long" and instead we should immediately + // stop the scheduler so that we don't enter "processQueue" anymore. scheduler.stop(); if (client2.stopping()) { if (debug.on()) { @@ -1888,7 +1833,11 @@ class Http2Connection { debug.log("Stopping scheduler", x); } } - Http2Connection.this.shutdown(x); + // terminate the connection + final Http2TerminationCause tc = (x != null) + ? Http2TerminationCause.forException(x) + : Http2TerminationCause.noErrorTermination(); + Http2Connection.this.close(tc); } } } @@ -1938,11 +1887,17 @@ class Http2Connection { @Override public void onComplete() { if (completed) return; - String msg = isActive() - ? "EOF reached while reading" - : "Idle connection closed by HTTP/2 peer"; - if (debug.on()) debug.log(msg); - errorRef.compareAndSet(null, new EOFException(msg)); + if (isActive()) { + final String msg = "EOF reached while reading"; + errorRef.compareAndSet(null, new EOFException(msg)); + if (debug.on()) { + debug.log(msg); + } + } else { + if (debug.on()) { + debug.log("HTTP/2 connection (with no active streams) closed by peer"); + } + } completed = true; runOrSchedule(); } @@ -1955,16 +1910,13 @@ class Http2Connection { dropped = true; } - void stop(Throwable error) { - if (errorRef.compareAndSet(null, error)) { - completed = true; - scheduler.stop(); - queue.clear(); - if (subscription != null) { - subscription.cancel(); - } - queue.clear(); + private void close() { + scheduler.stop(); + queue.clear(); + if (subscription != null) { + subscription.cancel(); } + queue.clear(); } } @@ -1990,6 +1942,7 @@ class Http2Connection { static final class ConnectionWindowUpdateSender extends WindowUpdateSender { final int initialWindowSize; + public ConnectionWindowUpdateSender(Http2Connection connection, int initialWindowSize) { super(connection, initialWindowSize); @@ -2004,13 +1957,9 @@ class Http2Connection { @Override protected boolean windowSizeExceeded(long received) { if (connection.isOpen()) { - try { - connection.protocolError(ErrorFrame.FLOW_CONTROL_ERROR, - "connection window exceeded (%s > %s)" - .formatted(received, windowSize)); - } catch (IOException io) { - connection.shutdown(io); - } + connection.protocolError(ErrorFrame.FLOW_CONTROL_ERROR, + "connection window exceeded (%s > %s)" + .formatted(received, windowSize)); } return true; } @@ -2033,72 +1982,144 @@ class Http2Connection { } } - private boolean isMarked(int state, int mask) { - return (state & mask) == mask; - } - - private boolean isMarkedForShutdown() { - final int closedSt = closedState; - return isMarked(closedSt, IDLE_SHUTDOWN_INITIATED) - || isMarked(closedSt, SHUTDOWN_REQUESTED); - } - - private boolean markShutdownRequested() { - return markClosedState(SHUTDOWN_REQUESTED); - } - - private boolean markHalfClosedLocal() { - return markClosedState(HALF_CLOSED_LOCAL); - } - - private boolean markHalfClosedRemote() { - return markClosedState(HALF_CLOSED_REMOTE); - } - - private boolean markIdleShutdownInitiated() { - return markClosedState(IDLE_SHUTDOWN_INITIATED); - } - - private boolean markClosedState(int flag) { - int state, desired; - do { - state = desired = closedState; - if ((state & flag) == flag) return false; - desired = state | flag; - } while (!CLOSED_STATE.compareAndSet(this, state, desired)); - return true; - } - - String describeClosedState(int state) { - if (state == 0) return "active"; - String desc = null; - if (isMarked(state, IDLE_SHUTDOWN_INITIATED)) { - desc = "idle-shutdown-initiated"; + private void sendGoAway(final GoAwayFrame goAway) { + // currently we send a GOAWAY just once irrespective of what value the + // last stream id was in the GOAWAY frame + if (!goAwaySent.compareAndSet(false, true)) { + // already sent + return; } - if (isMarked(state, SHUTDOWN_REQUESTED)) { - desc = desc == null ? "shutdown" : desc + "+shutdown"; + if (Log.trace()) { + Log.logTrace("{0} sending GOAWAY {1}", connection, goAway); + } else if (debug.on()) { + debug.log("sending GOAWAY " + goAway); } - if (isMarked(state, HALF_CLOSED_LOCAL | HALF_CLOSED_REMOTE)) { - if (desc == null) return "closed"; - else return desc + "+closed"; - } - if (isMarked(state, HALF_CLOSED_LOCAL)) { - if (desc == null) return "half-closed-local"; - else return desc + "+half-closed-local"; - } - if (isMarked(state, HALF_CLOSED_REMOTE)) { - if (desc == null) return "half-closed-remote"; - else return desc + "+half-closed-remote"; - } - return "0x" + Integer.toString(state, 16); + // this merely enqueues the frame + sendFrame(goAway); } - private static final VarHandle CLOSED_STATE; - static { - try { - CLOSED_STATE = MethodHandles.lookup().findVarHandle(Http2Connection.class, "closedState", int.class); - } catch (Exception x) { - throw new ExceptionInInitializerError(x); + /** + * Returns the termination cause if the connection is closed, else returns null. + */ + final Http2TerminationCause getTerminationCause() { + return this.connTerminator.determineTerminationCause(); + } + + // Responsible for doing all the necessary work for closing a Http2Connection + private final class Terminator { + // the cause for closing the connection. Must only be set in the + // Terminator.terminate(Http2TerminationCause) method. + private final AtomicReference terminationCause = new AtomicReference<>(); + // true if it has been decided to terminate the connection due to being idle, + // false otherwise. should be accessed only when holding the stateLock + private boolean chosenForIdleTermination; + + private void terminate(final Http2TerminationCause terminationCause) { + Objects.requireNonNull(terminationCause, "termination cause cannot be null"); + // allow to be terminated only once + stateLock.lock(); + try { + final boolean success = this.terminationCause.compareAndSet(null, terminationCause); + if (!success) { + // already terminated or is being terminated by some other thread + return; + } + // disable the idle timeout event, since we are now going to terminate the + // connection + Http2Connection.this.cancelIdleCloseEvent(); + } finally { + stateLock.unlock(); + } + // do the actual termination + doTerminate(); + } + + private void doTerminate() { + final Http2TerminationCause tc = terminationCause.get(); + assert tc != null : "missing termination cause"; + // we send a GOAWAY frame only if the remote side hasn't already indicated + // the intention to close the connection by previously sending a GOAWAY of its own + if (!Http2Connection.this.goAwayRecvd.get()) { + final int lastStream = 0; // TODO: set last stream. For now zero is ok. + final String peerVisibleReason = tc.getPeerVisibleReason(); + final GoAwayFrame goAway; + if (peerVisibleReason == null) { + goAway = new GoAwayFrame(lastStream, tc.getCloseCode()); + } else { + goAway = new GoAwayFrame(lastStream, tc.getCloseCode(), + peerVisibleReason.getBytes(UTF_8)); + } + sendGoAway(goAway); + } + // now close the connection + + if (Log.errors() || debug.on()) { + final String stateStr = "Abnormal close=" + tc.isAbnormalClose() + + ", has active streams=" + isActive() + + ", GOAWAY received=" + goAwayRecvd.get() + + ", GOAWAY sent=" + goAwaySent.get(); + if (Log.errors()) { + Log.logError("Closing connection {0} ({1}) due to: {2}", + connection, stateStr, tc); + } else { + debug.log("Closing connection (" + stateStr + ") due to: " + tc); + } + } + // close the TubeSubscriber + subscriber.close(); + client2.removeFromPool(Http2Connection.this); + // notify the HTTP/2 streams of the connection closure + for (final Stream s : streams.values()) { + try { + s.connectionClosing(tc.getCloseCause()); + } catch (Throwable e) { + Log.logError("Failed to close stream {0}: {1}", s.streamid, e); + } + } + // close the underlying connection + connection.close(tc.getCloseCause()); + } + + private void markForIdleTermination() { + assert stateLock.isHeldByCurrentThread() : Thread.currentThread() + + " not holding stateLock"; + this.chosenForIdleTermination = true; + } + + private boolean isMarkedForIdleTermination() { + assert stateLock.isHeldByCurrentThread() : Thread.currentThread() + + " not holding stateLock"; + return this.chosenForIdleTermination; + } + + private void idleTimedOut() { + if (debug.on()) { + debug.log("closing connection due to being idle"); + } + this.terminate(Http2TerminationCause.idleTimedOut()); + } + + /** + * Returns the termination cause for the connection. This method guarantees that if the + * {@linkplain Http2Connection#isOpen() connection is not open}, when this method is called, + * then it returns a non-null termination cause. Returns null if the connection is open. + */ + private Http2TerminationCause determineTerminationCause() { + final Http2TerminationCause tc = this.terminationCause.get(); + if (tc != null) { + // already terminated, return the cause + return tc; + } + if (!connection.channel().isOpen()) { + // if the underlying SocketChannel isn't open, then terminate the connection. + // that way when Http2Connection.isOpen() returns false in that situation, then this + // getTerminationCause() will return a termination cause. + terminate(Http2TerminationCause.forException(new ClosedChannelException())); + final Http2TerminationCause terminated = this.terminationCause.get(); + assert terminated != null : "missing termination cause"; + return terminated; + } + return null; // connection still open } } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2TerminationCause.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2TerminationCause.java new file mode 100644 index 00000000000..89b08cf8888 --- /dev/null +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2TerminationCause.java @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2025, 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 jdk.internal.net.http; + + +import java.io.IOException; +import java.net.ProtocolException; +import java.util.Objects; + +import jdk.internal.net.http.common.Utils; +import jdk.internal.net.http.frame.ErrorFrame; + +/** + * Termination cause for an {@linkplain Http2Connection HTTP/2 connection} + */ +public abstract sealed class Http2TerminationCause { + private String logMsg; + private String peerVisibleReason; + private final int closeCode; + private final Throwable originalCause; + private final IOException reportedCause; + + private Http2TerminationCause(final int closeCode, final Throwable closeCause) { + this.closeCode = closeCode; + this.originalCause = closeCause; + if (closeCause != null) { + this.logMsg = closeCause.toString(); + } + this.reportedCause = toReportedCause(this.originalCause, this.logMsg); + } + + private Http2TerminationCause(final int closeCode, final String loggedAs) { + this.closeCode = closeCode; + this.originalCause = null; + this.logMsg = loggedAs; + this.reportedCause = toReportedCause(null, this.logMsg); + } + + /** + * Returns the error code (specified for HTTP/2 ErrorFrame) that caused the + * connection termination. + */ + public final int getCloseCode() { + return this.closeCode; + } + + /** + * Returns the {@link IOException} that is considered the cause of the connection termination. + * Even a {@linkplain #isAbnormalClose() normal} termination will have + * an {@code IOException} associated with it, so this method will always return a non-null instance. + */ + public final IOException getCloseCause() { + return this.reportedCause; + } + + /** + * Returns {@code true} if the connection was terminated due to some exception. {@code false} + * otherwise. + * A normal connection termination (for example, the connection idle timing out locally) + * is not considered as an abnormal termination and this method returns {@code false} for + * such cases. + */ + public abstract boolean isAbnormalClose(); + + /** + * Returns the connection termination cause, represented as a string. Unlike the + * {@linkplain #getPeerVisibleReason() peer-visible reason}, this log message will not be + * sent across to the peer and it is thus allowed to include additional details that might + * help debugging a connection termination. + */ + public final String getLogMsg() { + return logMsg; + } + + /** + * Returns the connection termination cause, represented as a string. This represents the + * "debugData" that is sent to the peer in a + * {@linkplain jdk.internal.net.http.frame.GoAwayFrame GOAWAY frame}. + */ + public final String getPeerVisibleReason() { + return this.peerVisibleReason; + } + + /** + * Sets the connection termination cause, represented as a string, which will be sent + * to the peer in a {@linkplain jdk.internal.net.http.frame.GoAwayFrame GOAWAY frame}. + * Unlike the {@link #getLogMsg() log message}, + * it is expected that this peer-visible reason will not contain anything that is not meant + * to be viewed by the peer. + */ + protected final void setPeerVisibleReason(final String reasonPhrase) { + this.peerVisibleReason = reasonPhrase; + } + + /** + * Returns a connection termination cause that represents an + * {@linkplain #isAbnormalClose() abnormal} termination due to the given {@code cause}. + * + * @param cause the termination cause, cannot be null. + */ + public static Http2TerminationCause forException(final Throwable cause) { + Objects.requireNonNull(cause); + if (cause instanceof ProtocolException pe) { + return new ProtocolError(pe); + } + return new InternalError(cause); + } + + /** + * Returns a connection termination cause that represents a + * {@linkplain #isAbnormalClose() normal} termination. + */ + public static Http2TerminationCause noErrorTermination() { + return NoError.INSTANCE; + } + + /** + * Returns a connection termination cause that represents a + * {@linkplain #isAbnormalClose() normal} termination due to the connection + * being idle. + */ + public static Http2TerminationCause idleTimedOut() { + return NoError.IDLE_TIMED_OUT; + } + + /** + * Returns a connection termination cause that represents an + * {@linkplain #isAbnormalClose() abnormal} termination due to the given {@code errorCode}. + * Although this method does no checks for the {@code errorCode}, it is expected to be one + * of the error codes specified by the HTTP/2 RFC for the ErrorFrame. + * + * @param errorCode the error code + * @param loggedAs optional log message to be associated with this termination cause + */ + public static Http2TerminationCause forH2Error(final int errorCode, final String loggedAs) { + if (errorCode == ErrorFrame.PROTOCOL_ERROR) { + return new ProtocolError(loggedAs); + } else if (errorCode == ErrorFrame.FLOW_CONTROL_ERROR) { + // we treat flow control error as a protocol error currently + return new ProtocolError(loggedAs, true); + } + return new H2StandardError(errorCode, loggedAs); + } + + private static IOException toReportedCause(final Throwable original, + final String fallbackExceptionMsg) { + if (original == null) { + return fallbackExceptionMsg == null + ? new IOException("connection terminated") + : new IOException(fallbackExceptionMsg); + } else if (original instanceof IOException ioe) { + return ioe; + } else { + return Utils.toIOException(original); + } + } + + private static final class NoError extends Http2TerminationCause { + private static final IOException NO_ERROR_MARKER = + new IOException("HTTP/2 connection closed normally - no error"); + private static final IOException NO_ERROR_IDLE_TIMED_OUT_MARKER = + new IOException("HTTP/2 connection idle timed out - no error"); + + static { + // remove the stacktrace from the marker exception instances + NO_ERROR_MARKER.setStackTrace(new StackTraceElement[0]); + NO_ERROR_IDLE_TIMED_OUT_MARKER.setStackTrace(new StackTraceElement[0]); + } + + private static final NoError INSTANCE = new NoError(false); + private static final NoError IDLE_TIMED_OUT = new NoError(true); + + private final boolean idleTimedOut; + + private NoError(final boolean idleTimedOut) { + super(ErrorFrame.NO_ERROR, + idleTimedOut ? NO_ERROR_IDLE_TIMED_OUT_MARKER : NO_ERROR_MARKER); + this.idleTimedOut = idleTimedOut; + setPeerVisibleReason(idleTimedOut ? "idle timed out" : "no error"); + } + + @Override + public boolean isAbnormalClose() { + return false; + } + + @Override + public String toString() { + return this.idleTimedOut + ? "No error - idle timed out" + : "No error - normal termination"; + } + } + + private static sealed class H2StandardError extends Http2TerminationCause { + private H2StandardError(final int errCode, final String msg) { + super(errCode, msg); + setPeerVisibleReason(ErrorFrame.stringForCode(errCode)); + } + + private H2StandardError(final int errCode, final Throwable cause) { + super(errCode, cause); + setPeerVisibleReason(ErrorFrame.stringForCode(errCode)); + } + + @Override + public boolean isAbnormalClose() { + return getCloseCode() != ErrorFrame.NO_ERROR; + } + + @Override + public String toString() { + return ErrorFrame.stringForCode(this.getCloseCode()); + } + } + + private static final class ProtocolError extends H2StandardError { + private ProtocolError(final String msg) { + this(msg, false); + } + + private ProtocolError(final String msg, final boolean flowControlError) { + super(flowControlError + ? ErrorFrame.FLOW_CONTROL_ERROR + : ErrorFrame.PROTOCOL_ERROR, + new ProtocolException(msg)); + } + + private ProtocolError(final ProtocolException pe) { + super(ErrorFrame.PROTOCOL_ERROR, pe); + } + + @Override + public boolean isAbnormalClose() { + return true; + } + + @Override + public String toString() { + return "Protocol error - " + this.getLogMsg(); + } + } + + private static final class InternalError extends Http2TerminationCause { + private InternalError(final Throwable cause) { + super(ErrorFrame.INTERNAL_ERROR, cause); + } + + @Override + public boolean isAbnormalClose() { + return true; + } + + @Override + public String toString() { + return "Internal error - " + this.getLogMsg(); + } + } +} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java index b97a441881d..6bf1b9184f8 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java @@ -126,11 +126,16 @@ public final class Http3Connection implements AutoCloseable { // as per spec // -1 is used to imply no GOAWAY received so far private final AtomicLong lowestGoAwayReceipt = new AtomicLong(-1); + + private final Duration idleTimeoutDuration; private volatile IdleConnectionTimeoutEvent idleConnectionTimeoutEvent; // value of true implies no more streams will be initiated on this connection, // and the connection will be closed once the in-progress streams complete. private volatile boolean finalStream; private volatile boolean allowOnlyOneStream; + // true if this connection has been placed in the HTTP/3 connection pool of the HttpClient. + // false otherwise. + private volatile boolean presentInConnPool; // set to true if we decide to open a new connection // due to stream limit reached private volatile boolean streamLimitReached; @@ -220,6 +225,17 @@ public final class Http3Connection implements AutoCloseable { // in case of exception. Throws in the dependent // action after wrapping the exception if needed. .exceptionally(this::exceptionallyAndClose); + + this.idleTimeoutDuration = client.client().idleConnectionTimeout(HTTP_3).orElse(null); + if (idleTimeoutDuration == null) { + // The absence of HTTP/3 idle timeout duration is considered to mean + // never idle terminating the connection + quicConnection.connectionTerminator().appLayerMaxIdle(Duration.MAX, + this::isQUICTrafficGenerationRequired); + } else { + quicConnection.connectionTerminator().appLayerMaxIdle(idleTimeoutDuration, + this::isQUICTrafficGenerationRequired); + } if (Log.http3()) { Log.logHttp3("HTTP/3 connection created for " + quicConnectionTag() + " - local address: " + quicConnection.localAddress()); @@ -545,7 +561,28 @@ public final class Http3Connection implements AutoCloseable { if (debug.on()) debug.log("Reference h3 stream: " + streamId); client.client.h3StreamReference(); exchanges.put(streamId, exchange); - exchange.start(); + // It's possible that the connection will have been closed + // by the time we reach here. + // We need to double-check that the connection is still opened + // after having put the exchange to the exchanges map. + if (isOpen()) { + // only start the exchange if the connection is + // still open + exchange.start(); + } else { + // Otherwise mark the exchange as unprocessed since we haven't + // sent the headers yet and the connection got closed + // before we started the exchange. + TerminationCause tc = quicConnection.terminationCause(); + if (Log.http3()) { + Log.logHttp3("HTTP/3 exchange for {0}/streamId={1} unprocessed due to {2}", + quicConnectionTag(), Long.toString(streamId), tc.getCloseCause()); + } + exchange.exchange.markUnprocessedByPeer(); + exchange.cancelImpl(tc.getCloseCause(), + Http3Error.fromCode(tc.getCloseCode()).orElse(H3_NO_ERROR)); + } + // OK to return the exchange even if already closed return exchange; } @@ -732,9 +769,8 @@ public final class Http3Connection implements AutoCloseable { try { var te = idleConnectionTimeoutEvent; if (te == null && exchangeStreams.isEmpty()) { - te = idleConnectionTimeoutEvent = client.client().idleConnectionTimeout(HTTP_3) - .map(IdleConnectionTimeoutEvent::new).orElse(null); - if (te != null) { + if (idleTimeoutDuration != null) { + te = idleConnectionTimeoutEvent = new IdleConnectionTimeoutEvent(); client.client().registerTimer(te); } } @@ -873,6 +909,48 @@ public final class Http3Connection implements AutoCloseable { } } + /** + * Mark this connection as being present or absent from the connection pool. + */ + void setPooled(final boolean present) { + this.presentInConnPool = present; + } + + /** + * This callback method is invoked by the QUIC layer when it notices that this + * connection hasn't seen any traffic for certain period of time. QUIC + * invokes this method to ask HTTP/3 whether the QUIC layer + * should generate traffic to keep this connection active. + * This method returns true, indicating that the traffic must be generated, + * if this HTTP/3 connection is in pool and there's no current request/response + * in progress over this connection (i.e. the HTTP/3 connection is idle in the + * pool waiting for any new requests to be issued by the application). + */ + private boolean isQUICTrafficGenerationRequired() { + if (!isOpen()) { + return false; + } + lock(); + try { + // if there's no HTTP/3 request/responses in progress and the connection is + // in the pool (thus idle), then we instruct QUIC to generate traffic on the + // QUIC connection to prevent it from being idle terminated. + final boolean generateTraffic = this.presentInConnPool + && this.exchanges.isEmpty() + && this.reservedStreamCount.get() == 0 + // a connection in the pool could be marked as + // finalStream (for example when it receives a GOAWAY). we don't want + // to generate explicit QUIC traffic for such connections too. + && !this.finalStream; + if (debug.on()) { + debug.log("QUIC traffic generation required = " + generateTraffic); + } + return generateTraffic; + } finally { + unlock(); + } + } + /** * Cancels any event that might have been scheduled to shutdown this connection. Must be called * with the stateLock held. @@ -893,8 +971,9 @@ public final class Http3Connection implements AutoCloseable { private boolean cancelled; private boolean idleShutDownInitiated; - IdleConnectionTimeoutEvent(Duration duration) { - super(duration); + IdleConnectionTimeoutEvent() { + assert idleTimeoutDuration != null : "idle timeout duration is null"; + super(idleTimeoutDuration); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java index eaacd8213cb..0f1fe2b7abf 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java @@ -155,23 +155,34 @@ class Http3ConnectionPool { assert key.equals(c.key()); var altService = c.connection().getSourceAltService().orElse(null); if (altService != null && altService.wasAdvertised()) { - return advertised.putIfAbsent(key, c); + final var prev = advertised.putIfAbsent(key, c); + if (prev == null) { + c.setPooled(true); // mark the newly pooled connection as pooled + } + return prev; } assert altService == null || altService.originHasSameAuthority(); - return unadvertised.putIfAbsent(key, c); + final var prev = unadvertised.putIfAbsent(key, c); + if (prev == null) { + c.setPooled(true); // mark the newly pooled connection as pooled + } + return prev; } - Http3Connection put(String key, Http3Connection c) { + void put(String key, Http3Connection c) { Objects.requireNonNull(key); Objects.requireNonNull(c); assert key.equals(c.key()) : "key mismatch %s -> %s" .formatted(key, c.key()); var altService = c.connection().getSourceAltService().orElse(null); if (altService != null && altService.wasAdvertised()) { - return advertised.put(key, c); + advertised.put(key, c); + c.setPooled(true); + return; } assert altService == null || altService.originHasSameAuthority(); - return unadvertised.put(key, c); + unadvertised.put(key, c); + c.setPooled(true); } boolean remove(String key, Http3Connection c) { @@ -189,11 +200,17 @@ class Http3ConnectionPool { } assert altService == null || altService.originHasSameAuthority(); - return unadvertised.remove(key, c); + final boolean removed = unadvertised.remove(key, c); + if (removed) { + c.setPooled(false); + } + return removed; } void clear() { + advertised.values().forEach((c) -> c.setPooled(false)); advertised.clear(); + unadvertised.values().forEach((c) -> c.setPooled(false)); unadvertised.clear(); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java index 41a4a84958a..81475a47c4a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java @@ -554,8 +554,12 @@ final class Http3ExchangeImpl extends Http3Stream { } final class Http3StreamResponseSubscriber extends HttpBodySubscriberWrapper { - Http3StreamResponseSubscriber(BodySubscriber subscriber) { + + private final boolean cancelTimerOnTermination; + + Http3StreamResponseSubscriber(BodySubscriber subscriber, boolean cancelTimerOnTermination) { super(subscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; } @Override @@ -568,6 +572,13 @@ final class Http3ExchangeImpl extends Http3Stream { registerResponseSubscriber(this); } + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.multi.cancelTimer(); + } + } + @Override protected void logComplete(Throwable error) { if (error == null) { @@ -590,9 +601,10 @@ final class Http3ExchangeImpl extends Http3Stream { Http3StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { if (debug.on()) debug.log("Creating body subscriber"); - Http3StreamResponseSubscriber subscriber = - new Http3StreamResponseSubscriber<>(handler.apply(response)); - return subscriber; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http3StreamResponseSubscriber<>(handler.apply(response), cancelTimerOnTermination); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index 6ea196a4d1c..ff130e90358 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java @@ -53,6 +53,7 @@ import java.security.NoSuchAlgorithmException; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -98,6 +99,7 @@ import jdk.internal.net.http.common.OperationTrackers.Trackable; import jdk.internal.net.http.common.OperationTrackers.Tracker; import jdk.internal.net.http.common.Utils.SafeExecutor; import jdk.internal.net.http.common.Utils.SafeExecutorService; +import jdk.internal.net.http.common.Utils.UseVTForSelector; import jdk.internal.net.http.websocket.BuilderImpl; import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; @@ -125,6 +127,18 @@ final class HttpClientImpl extends HttpClient implements Trackable { // Defaults to value used for HTTP/1 Keep-Alive Timeout. Can be overridden by jdk.httpclient.keepalive.timeout.h2 property. static final long IDLE_CONNECTION_TIMEOUT_H2 = getTimeoutProp("jdk.httpclient.keepalive.timeout.h2", KEEP_ALIVE_TIMEOUT); static final long IDLE_CONNECTION_TIMEOUT_H3 = getTimeoutProp("jdk.httpclient.keepalive.timeout.h3", IDLE_CONNECTION_TIMEOUT_H2); + private final boolean hasRequiredH3TLS; + private final boolean hasRequiredH2TLS; + + static final UseVTForSelector USE_VT_FOR_SELECTOR = + Utils.useVTForSelector("jdk.internal.httpclient.tcp.selector.useVirtualThreads", "default"); + private static boolean useVtForSelector() { + return switch (USE_VT_FOR_SELECTOR) { + case ALWAYS -> true; + case NEVER -> false; + default -> true; + }; + } // Define the default factory as a static inner class // that embeds all the necessary logic to avoid @@ -293,7 +307,6 @@ final class HttpClientImpl extends HttpClient implements Trackable { if (pending.cf.isDone()) return res; var client = pending.client; - var cf = pending.cf; var id = pending.id; boolean added = client.pendingRequests.add(pending); // this may immediately remove `pending` from the set is the cf is already completed @@ -342,6 +355,7 @@ final class HttpClientImpl extends HttpClient implements Trackable { private final boolean isDefaultExecutor; private final SSLContext sslContext; private final SSLParameters sslParams; + private final Thread selmgrThread; private final SelectorManager selmgr; private final FilterFactory filters; private final Http2ClientImpl client2; @@ -466,10 +480,17 @@ final class HttpClientImpl extends HttpClient implements Trackable { "HTTP3 is not supported")); } sslParams = requireNonNullElseGet(builder.sslParams, sslContext::getDefaultSSLParameters); - boolean sslParamsSupportedForH3 = sslParams.getProtocols() == null - || sslParams.getProtocols().length == 0 - || isQuicCompatible(sslParams); - if (version == Version.HTTP_3 && !sslParamsSupportedForH3) { + String[] sslProtocols = sslParams.getProtocols(); + if (sslProtocols == null) { + sslProtocols = requireNonNullElseGet(sslContext.getDefaultSSLParameters().getProtocols(), + () -> new String[0]); + } + // HTTP/3 MUST use TLS version 1.3 or higher + hasRequiredH3TLS = Arrays.asList(sslProtocols).contains("TLSv1.3"); + // HTTP/2 MUST use TLS version 1.2 or higher for HTTP/2 over TLS + hasRequiredH2TLS = hasRequiredH3TLS || Arrays.asList(sslProtocols).contains("TLSv1.2"); + + if (version == Version.HTTP_3 && !hasRequiredH3TLS) { throw new UncheckedIOException(new UnsupportedProtocolVersionException( "HTTP3 is not supported - TLSv1.3 isn't configured on SSLParameters")); } @@ -496,7 +517,7 @@ final class HttpClientImpl extends HttpClient implements Trackable { debug.log("proxySelector is %s (user-supplied=%s)", this.proxySelector, userProxySelector != null); authenticator = builder.authenticator; - boolean h3Supported = sslCtxSupportedForH3 && sslParamsSupportedForH3; + boolean h3Supported = sslCtxSupportedForH3 && hasRequiredH3TLS; registry = new AltServicesRegistry(id); connections = new ConnectionPool(id); client2 = new Http2ClientImpl(this); @@ -509,12 +530,32 @@ final class HttpClientImpl extends HttpClient implements Trackable { // unlikely throw new UncheckedIOException(e); } - selmgr.setDaemon(true); + selmgrThread = useVtForSelector() + ? Thread.ofVirtual().name("HttpClient-" + id + "-SelectorManager") + .inheritInheritableThreadLocals(false).unstarted(selmgr) + : Thread.ofPlatform().name("HttpClient-" + id + "-SelectorManager") + .inheritInheritableThreadLocals(false).daemon().unstarted(selmgr); filters = new FilterFactory(); initFilters(); assert facadeRef.get() != null; } + /** + * Returns true if the SSL parameter protocols contains at + * least one TLS version that HTTP/3 requires. + */ + boolean hasRequiredHTTP3TLSVersion() { + return hasRequiredH3TLS; + } + + /** + * Returns true if the SSL parameter protocols contains at + * least one TLS version that HTTP/2 requires. + */ + boolean hasRequiredHTTP2TLSVersion() { + return hasRequiredH2TLS; + } + // called when the facade is GC'ed. // Just wakes up the selector to cleanup... void facadeCleanup() { @@ -528,7 +569,7 @@ final class HttpClientImpl extends HttpClient implements Trackable { private void start() { try { - selmgr.start(); + selmgrThread.start(); } catch (Throwable t) { isStarted.set(true); throw t; @@ -635,7 +676,7 @@ final class HttpClientImpl extends HttpClient implements Trackable { @Override public boolean awaitTermination(Duration duration) throws InterruptedException { // Implicit NPE will be thrown if duration is null - return selmgr.join(duration); + return selmgrThread.join(duration); } @Override @@ -927,7 +968,7 @@ final class HttpClientImpl extends HttpClient implements Trackable { } boolean isSelectorThread() { - return Thread.currentThread() == selmgr; + return Thread.currentThread() == selmgrThread; } AltServicesRegistry registry() { return registry; } @@ -1157,7 +1198,7 @@ final class HttpClientImpl extends HttpClient implements Trackable { } // Main loop for this client's selector - private static final class SelectorManager extends Thread { + private static final class SelectorManager implements Runnable { // For testing purposes we have an internal System property that // can control the frequency at which the selector manager will wake @@ -1196,9 +1237,6 @@ final class HttpClientImpl extends HttpClient implements Trackable { private final ReentrantLock lock = new ReentrantLock(); SelectorManager(HttpClientImpl ref) throws IOException { - super(null, null, - "HttpClient-" + ref.id + "-SelectorManager", - 0, false); owner = ref; debug = ref.debug; debugtimeout = ref.debugtimeout; @@ -1221,7 +1259,7 @@ final class HttpClientImpl extends HttpClient implements Trackable { } void eventUpdated(AsyncEvent e) throws ClosedChannelException { - if (Thread.currentThread() == this) { + if (owner.isSelectorThread()) { SelectionKey key = e.channel().keyFor(selector); if (key != null && key.isValid()) { SelectorAttachment sa = (SelectorAttachment) key.attachment(); @@ -1315,8 +1353,19 @@ final class HttpClientImpl extends HttpClient implements Trackable { if (!inSelectorThread) selector.wakeup(); } + String getName() { + return owner.selmgrThread.getName(); + } + // Only called by the selector manager thread private void shutdown() { + // first stop the client to avoid seeing exceptions + // about "selector manager closed" + Log.logTrace("{0}: stopping", owner.dbgTag); + try { + owner.stop(); + } catch (Throwable ignored) { + } try { lock.lock(); try { @@ -1329,6 +1378,7 @@ final class HttpClientImpl extends HttpClient implements Trackable { } } catch (IOException ignored) { } finally { + // cleanup anything that might have been left behind owner.stop(); } } @@ -1830,6 +1880,13 @@ final class HttpClientImpl extends HttpClient implements Trackable { } } + // Visible for tests + List timers() { + synchronized (this) { + return new ArrayList<>(timeouts); + } + } + /** * Purges ( handles ) timer events that have passed their deadline, and * returns the amount of time, in milliseconds, until the next earliest diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java index 0219b0960d7..0c1388cec8a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java @@ -32,7 +32,6 @@ import java.net.http.HttpResponse; import java.nio.ByteBuffer; import java.nio.channels.NetworkChannel; import java.nio.channels.SocketChannel; -import java.util.Arrays; import java.util.Comparator; import java.util.IdentityHashMap; import java.util.List; @@ -43,8 +42,6 @@ import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.Flow; import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiPredicate; -import java.util.function.Predicate; -import java.net.http.HttpClient; import java.net.http.HttpClient.Version; import java.net.http.HttpHeaders; @@ -285,23 +282,6 @@ abstract class HttpConnection implements Closeable { */ abstract HttpPublisher publisher(); - // HTTP/2 MUST use TLS version 1.2 or higher for HTTP/2 over TLS - private static final Predicate testRequiredHTTP2TLSVersion = proto -> - proto.equals("TLSv1.2") || proto.equals("TLSv1.3"); - - /** - * Returns true if the given client's SSL parameter protocols contains at - * least one TLS version that HTTP/2 requires. - */ - private static final boolean hasRequiredHTTP2TLSVersion(HttpClient client) { - String[] protos = client.sslParameters().getProtocols(); - if (protos != null) { - return Arrays.stream(protos).filter(testRequiredHTTP2TLSVersion).findAny().isPresent(); - } else { - return false; - } - } - /** * Factory for retrieving HttpConnections. A connection can be retrieved * from the connection pool, or a new one created if none available. @@ -359,7 +339,7 @@ abstract class HttpConnection implements Closeable { } else { assert !request.isHttp3Only(version); // should have failed before String[] alpn = null; - if (version == HTTP_2 && hasRequiredHTTP2TLSVersion(client)) { + if (version == HTTP_2 && client.hasRequiredHTTP2TLSVersion()) { // We only come here after we have checked the HTTP/2 connection pool. // We will not negotiate HTTP/2 if we don't have the appropriate TLS version alpn = new String[] { Alpns.H2, Alpns.HTTP_1_1 }; @@ -540,9 +520,7 @@ abstract class HttpConnection implements Closeable { * Closes this connection due to the given cause. * @param cause the cause for which the connection is closed, may be null */ - void close(Throwable cause) { - close(); - } + abstract void close(Throwable cause); /** * {@return the underlying connection flow, if applicable} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java index 0a22256f6c6..36f191fbd67 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java @@ -31,11 +31,9 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.SocketOption; import java.net.URI; -import java.net.http.HttpClient; import java.net.http.HttpConnectTimeoutException; import java.nio.channels.NetworkChannel; import java.time.Duration; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -43,7 +41,6 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.function.Function; -import java.util.function.Predicate; import javax.net.ssl.SNIServerName; import javax.net.ssl.SSLParameters; @@ -81,9 +78,6 @@ abstract class HttpQuicConnection extends HttpConnection { // the alt-service which was advertised, from some origin, for this connection co-ordinates. // can be null, which indicates this wasn't created because of an alt-service private final AltService sourceAltService; - // HTTP/2 MUST use TLS version 1.3 or higher for HTTP/3 over TLS - private static final Predicate testRequiredHTTP3TLSVersion = proto -> - proto.equals("TLSv1.3"); HttpQuicConnection(Origin originServer, InetSocketAddress address, HttpClientImpl client, @@ -178,19 +172,6 @@ abstract class HttpQuicConnection extends HttpConnection { return quicConnection; } - /** - * Returns true if the given client's SSL parameter protocols contains at - * least one TLS version that HTTP/3 requires. - */ - private static boolean hasRequiredHTTP3TLSVersion(HttpClient client) { - String[] protos = client.sslParameters().getProtocols(); - if (protos != null) { - return Arrays.stream(protos).anyMatch(testRequiredHTTP3TLSVersion); - } else { - return false; - } - } - /** * Called when the HTTP/3 connection is established, either successfully or * unsuccessfully @@ -260,7 +241,7 @@ abstract class HttpQuicConnection extends HttpConnection { // to using HTTP/2 var debug = h3client.debug(); var where = "HttpQuicConnection.getHttpQuicConnection"; - if (proxy != null || !hasRequiredHTTP3TLSVersion(client)) { + if (proxy != null || !client.hasRequiredHTTP3TLSVersion()) { if (debug.on()) debug.log("%s: proxy required or SSL version mismatch", where); return null; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java index ec621f7f955..60eb55ec0ad 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java @@ -25,7 +25,6 @@ package jdk.internal.net.http; -import java.io.IOError; import java.io.IOException; import java.lang.ref.WeakReference; import java.net.ConnectException; @@ -254,7 +253,7 @@ class MultiExchange implements Cancelable { .map(ConnectTimeoutTracker::getRemaining); } - private void cancelTimer() { + void cancelTimer() { if (responseTimerEvent != null) { client.cancelTimer(responseTimerEvent); responseTimerEvent = null; @@ -404,6 +403,8 @@ class MultiExchange implements Cancelable { processAltSvcHeader(r, client(), currentreq); Exchange exch = getExchange(); if (bodyNotPermitted(r)) { + // No response body consumption is expected, we can cancel the timer right away + cancelTimer(); if (bodyIsPresent(r)) { IOException ioe = new IOException( "unexpected content length header with 204 response"); @@ -467,6 +468,8 @@ class MultiExchange implements Cancelable { private CompletableFuture responseAsyncImpl(final boolean applyReqFilters) { if (currentreq.timeout().isPresent()) { + // Retried/Forwarded requests should reset the timer, if present + cancelTimer(); responseTimerEvent = ResponseTimerEvent.of(this); client.registerTimer(responseTimerEvent); } @@ -502,7 +505,6 @@ class MultiExchange implements Cancelable { } return completedFuture(response); } else { - cancelTimer(); setNewResponse(currentreq, response, null, exch); if (currentreq.isWebSocket()) { // need to close the connection and open a new one. @@ -520,11 +522,18 @@ class MultiExchange implements Cancelable { } }) .handle((response, ex) -> { // 5. handle errors and cancel any timer set - cancelTimer(); if (ex == null) { assert response != null; return completedFuture(response); } + + // Cancel the timer. Note that we only do so if the + // response has completed exceptionally. That is, we don't + // cancel the timer if there are no exceptions, since the + // response body might still get consumed, and it is + // still subject to the response timer. + cancelTimer(); + // all exceptions thrown are handled here final RetryContext retryCtx = checkRetryEligible(ex, exch); assert retryCtx != null : "retry context is null"; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java index e705aae72a1..45d242df671 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java @@ -311,20 +311,20 @@ class PlainHttpConnection extends HttpConnection { var connectTimerEvent = this.connectTimerEvent; if (connectTimerEvent != null) client().cancelTimer(connectTimerEvent); - if (Log.channel()) { - Log.logChannel("Closing channel: " + chan); - } - try { - tube.signalClosed(errorRef.get()); - chan.close(); - } finally { - client().connectionClosed(this); - } + } finally { + stateLock.unlock(); + } + if (Log.channel()) { + Log.logChannel("Closing channel: " + chan); + } + try { + tube.signalClosed(errorRef.get()); + chan.close(); } catch (IOException e) { debug.log("Closing resulted in " + e); Log.logTrace("Closing resulted in " + e); } finally { - stateLock.unlock(); + client().connectionClosed(this); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index 4b59a777de2..bf9170f8f51 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -31,7 +31,6 @@ import java.io.UncheckedIOException; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.net.ProtocolException; -import java.net.URI; import java.net.http.HttpResponse.BodyHandler; import java.net.http.HttpResponse.ResponseInfo; import java.nio.ByteBuffer; @@ -391,9 +390,10 @@ class Stream extends ExchangeImpl { @Override Http2StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { - Http2StreamResponseSubscriber subscriber = - new Http2StreamResponseSubscriber<>(handler.apply(response)); - return subscriber; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http2StreamResponseSubscriber<>(handler.apply(response), cancelTimerOnTermination); } // The Http2StreamResponseSubscriber is registered with the HttpClient @@ -973,36 +973,6 @@ class Stream extends ExchangeImpl { return headers; } - private static HttpHeaders createPseudoHeaders(HttpRequest request) { - HttpHeadersBuilder hdrs = new HttpHeadersBuilder(); - String method = request.method(); - hdrs.setHeader(":method", method); - URI uri = request.uri(); - hdrs.setHeader(":scheme", uri.getScheme()); - String host = uri.getHost(); - int port = uri.getPort(); - assert host != null; - if (port != -1) { - hdrs.setHeader(":authority", host + ":" + port); - } else { - hdrs.setHeader(":authority", host); - } - String query = uri.getRawQuery(); - String path = uri.getRawPath(); - if (path == null || path.isEmpty()) { - if (method.equalsIgnoreCase("OPTIONS")) { - path = "*"; - } else { - path = "/"; - } - } - if (query != null) { - path += "?" + query; - } - hdrs.setHeader(":path", Utils.encode(path)); - return hdrs.build(); - } - HttpHeaders getRequestPseudoHeaders() { return requestPseudoHeaders; } @@ -1725,6 +1695,11 @@ class Stream extends ExchangeImpl { .whenComplete((v, t) -> pushGroup.pushError(t)); } + @Override + Http2StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { + return new Http2StreamResponseSubscriber(handler.apply(response), false); + } + @Override void completeResponse(Response r) { Log.logResponse(r::toString); @@ -1955,8 +1930,12 @@ class Stream extends ExchangeImpl { } final class Http2StreamResponseSubscriber extends HttpBodySubscriberWrapper { - Http2StreamResponseSubscriber(BodySubscriber subscriber) { + + private final boolean cancelTimerOnTermination; + + Http2StreamResponseSubscriber(BodySubscriber subscriber, boolean cancelTimerOnTermination) { super(subscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; } @Override @@ -1969,6 +1948,13 @@ class Stream extends ExchangeImpl { unregisterResponseSubscriber(this); } + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.multi.cancelTimer(); + } + } + } private static final VarHandle DEREGISTERED; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java index 1c483ce99f4..f1c1f6f2d2a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,7 +33,6 @@ import java.util.Objects; import java.util.concurrent.CompletionStage; import java.util.concurrent.Flow; import java.util.concurrent.Flow.Subscription; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; @@ -51,7 +50,6 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { public static final Comparator> COMPARE_BY_ID = Comparator.comparing(HttpBodySubscriberWrapper::id); - public static final Flow.Subscription NOP = new Flow.Subscription() { @Override public void request(long n) { } @@ -75,7 +73,18 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { this.userSubscriber = userSubscriber; } - private class SubscriptionWrapper implements Subscription { + /** + * A callback to be invoked before termination, whether due to the + * completion or failure of the subscriber, or cancellation of the + * subscription. To be precise, this method is called before + * {@link #onComplete()}, {@link #onError(Throwable) onError()}, or + * {@link #onCancel()}. + */ + protected void onTermination() { + // Do nothing + } + + private final class SubscriptionWrapper implements Subscription { final Subscription subscription; SubscriptionWrapper(Subscription s) { this.subscription = Objects.requireNonNull(s); @@ -92,6 +101,7 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { subscription.cancel(); } finally { if (markCancelled()) { + onTermination(); onCancel(); } } @@ -284,6 +294,7 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { */ public final void complete(Throwable t) { if (markCompleted()) { + onTermination(); logComplete(t); tryUnregister(); t = withError = Utils.getCompletionCause(t); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java index a02506cff5c..20b0338215c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java @@ -242,6 +242,15 @@ public final class Utils { return true; }; + public enum UseVTForSelector { ALWAYS, NEVER, DEFAULT } + + public static UseVTForSelector useVTForSelector(String property, String defval) { + String useVtForSelector = System.getProperty(property, defval); + return Stream.of(UseVTForSelector.values()) + .filter((v) -> v.name().equalsIgnoreCase(useVtForSelector)) + .findFirst().orElse(UseVTForSelector.DEFAULT); + } + public static T addSuppressed(T x, Throwable suppressed) { if (x != suppressed && suppressed != null) { var sup = x.getSuppressed(); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java index 24230a0883d..14559db4a11 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java @@ -24,15 +24,77 @@ */ package jdk.internal.net.http.quic; -// responsible for managing the connection termination of a QUIC connection +import java.time.Duration; +import java.util.function.Supplier; + +/** + * Responsible for managing the connection termination of a QUIC connection + */ public sealed interface ConnectionTerminator permits ConnectionTerminatorImpl { - // lets the terminator know that the connection is still alive and should not be - // idle timed out - void keepAlive(); + /** + * Instructs the connection terminator to consider the connection as active + * at the present point in time. The connection terminator will then restart its + * idle timeout timer from this point in time. + *

    + * This method must be called when an incoming packet is processed successfully + * or when an ack-eliciting packet is sent by the local endpoint on the connection. + */ + void markActive(); + /** + * Terminates the connection, if not already terminated, with the given cause. + *

    + * A connection is terminated only once with a {@link TerminationCause}. However, this method + * can be called any number of times. If the connection is not already terminated, + * then this method does the necessary work to terminate the connection. Any subsequent + * invocations of this method, after the connection has been terminated, will not + * change the termination cause of the connection. + * + * @param cause the termination cause + */ void terminate(TerminationCause cause); + /** + * Returns {@code true} if the connection is allowed for use, {@code false} otherwise. + *

    + * This method is typically called when a connection that has been idle, is about to be used + * for handling some request. This method allows for co-ordination between the connection usage + * and the connection terminator to prevent the connection from being idle timed out when it is + * about to be used for some request. The connection must only be used if this method + * returns {@code true}. + * + * @return true if the connection can be used, false otherwise + */ boolean tryReserveForUse(); + /** + * Instructs the connection terminator that the application layer allows the + * connection to stay idle for the given {@code maxIdle} duration. If the QUIC + * layer has negotiated an idle timeout for the connection, that's lower than + * the application's {@code maxIdle} duration, then the connection terminator + * upon noticing absence of traffic over the connection for certain duration, + * calls the {@code trafficGenerationCheck} to check if the QUIC layer should + * explicitly generate some traffic to prevent the connection + * from idle terminating. + *

    + * When the {@code trafficGenerationCheck} is invoked, the application layer + * must return {@code true} only if explicit traffic generation is necessary + * to keep the connection alive. + *

    + * If the application layer wishes to never idle terminate the connection, then + * a {@code maxIdle} duration of {@linkplain Duration#MAX Duration.MAX} is recommended. + * + * @param maxIdle the maximum idle duration of the connection, + * at the application layer + * @param trafficGenerationCheck the callback that will be invoked by the connection + * terminator to decide if the QUIC layer should generate + * any traffic to prevent the connection from idle terminating + * @throws NullPointerException if either {@code maxIdle} or {@code trafficGenerationCheck} + * is null + * @throws IllegalArgumentException if {@code maxIdle} is + * {@linkplain Duration#isNegative() negative} or + * {@linkplain Duration#isZero() zero} + */ + void appLayerMaxIdle(Duration maxIdle, Supplier trafficGenerationCheck); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java index 150d6233953..7870f4f1d8e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java @@ -25,11 +25,13 @@ package jdk.internal.net.http.quic; import java.nio.ByteBuffer; +import java.time.Duration; import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import java.util.function.Supplier; import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Logger; @@ -52,7 +54,6 @@ import static jdk.internal.net.http.quic.QuicConnectionImpl.QuicConnectionState. import static jdk.internal.net.http.quic.TerminationCause.appLayerClose; import static jdk.internal.net.http.quic.TerminationCause.forSilentTermination; import static jdk.internal.net.http.quic.TerminationCause.forTransportError; -import static jdk.internal.net.quic.QuicTransportErrors.INTERNAL_ERROR; import static jdk.internal.net.quic.QuicTransportErrors.NO_ERROR; final class ConnectionTerminatorImpl implements ConnectionTerminator { @@ -70,8 +71,8 @@ final class ConnectionTerminatorImpl implements ConnectionTerminator { } @Override - public void keepAlive() { - this.connection.idleTimeoutManager.keepAlive(); + public void markActive() { + this.connection.idleTimeoutManager.markActive(); } @Override @@ -79,6 +80,11 @@ final class ConnectionTerminatorImpl implements ConnectionTerminator { return this.connection.idleTimeoutManager.tryReserveForUse(); } + @Override + public void appLayerMaxIdle(final Duration maxIdle, final Supplier trafficGenerationCheck) { + this.connection.idleTimeoutManager.appLayerMaxIdle(maxIdle, trafficGenerationCheck); + } + @Override public void terminate(final TerminationCause cause) { Objects.requireNonNull(cause); @@ -143,8 +149,9 @@ final class ConnectionTerminatorImpl implements ConnectionTerminator { Log.logError("{0}: stateless reset from peer ({1})", connection.logTag(), (peerIsServer ? "server" : "client")); } + var label = "quic:" + connection.uniqueId(); final SilentTermination st = forSilentTermination("stateless reset from peer (" - + (peerIsServer ? "server" : "client") + ")"); + + (peerIsServer ? "server" : "client") + ") on " + label); terminate(st); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java index a7469f18ed8..375a0dc8e16 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/IdleTimeoutManager.java @@ -24,12 +24,15 @@ */ package jdk.internal.net.http.quic; +import java.time.Duration; import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; import jdk.internal.net.http.common.Deadline; import jdk.internal.net.http.common.Log; @@ -58,17 +61,21 @@ final class IdleTimeoutManager { private IdleTimeoutEvent idleTimeoutEvent; // must be accessed only when holding stateLock private StreamDataBlockedEvent streamDataBlockedEvent; - // the time at which the last outgoing packet was sent or an + // the time (in nanos) at which the last outgoing packet was sent or an // incoming packet processed on the connection - private volatile long lastPacketActivityAt; + private volatile long lastPacketActivityNanos; private final ReentrantLock idleTerminationLock = new ReentrantLock(); // true if it has been decided to terminate the connection due to being idle, // false otherwise. should be accessed only when holding the idleTerminationLock private boolean chosenForIdleTermination; - // the time at which the connection was last reserved for use. + // the time (in nanos) at which the connection was last reserved for use. // should be accessed only when holding the idleTerminationLock - private long lastUsageReservationAt; + private long lastUsageReservationNanos; + + private final AtomicReference> trafficGenerationCheck = new AtomicReference<>(); + // must be accessed only when holding stateLock + private PingEvent pingEvent; IdleTimeoutManager(final QuicConnectionImpl connection) { this.connection = Objects.requireNonNull(connection, "connection"); @@ -79,28 +86,12 @@ final class IdleTimeoutManager { * Starts the idle timeout management for the connection. This should be called * after the handshake is complete for the connection. * - * @throw IllegalStateException if handshake hasn't yet completed or if the handshake - * has failed for the connection + * @throws IllegalStateException if handshake hasn't yet completed or if the handshake + * has failed for the connection */ void start() { - final CompletableFuture handshakeCF = - this.connection.handshakeFlow().handshakeCF(); // start idle management only for successfully completed handshake - if (!handshakeCF.isDone()) { - throw new IllegalStateException("handshake isn't yet complete," - + " cannot start idle connection management"); - } - if (handshakeCF.isCompletedExceptionally()) { - throw new IllegalStateException("cannot start idle connection management for a failed" - + " connection"); - } - startTimers(); - } - - /** - * Starts the idle timeout timer of the QUIC connection, if not already started. - */ - private void startTimers() { + requireSuccessfulHandshake(); if (shutdown.get()) { return; } @@ -116,6 +107,19 @@ final class IdleTimeoutManager { } } + private void requireSuccessfulHandshake() { + final CompletableFuture handshakeCF = + this.connection.handshakeFlow().handshakeCF(); + if (!handshakeCF.isDone()) { + throw new IllegalStateException("handshake isn't yet complete," + + " cannot use idle connection management"); + } + if (handshakeCF.isCompletedExceptionally()) { + throw new IllegalStateException("cannot use idle connection management for a failed" + + " connection"); + } + } + private void startIdleTerminationTimer() { assert stateLock.isHeldByCurrentThread() : "not holding state lock"; final Optional idleTimeoutMillis = getIdleTimeout(); @@ -154,18 +158,14 @@ final class IdleTimeoutManager { } final QuicEndpoint endpoint = this.connection.endpoint(); assert endpoint != null : "QUIC endpoint is null"; - // disable the event (refreshDeadline() of IdleTimeoutEvent will return Deadline.MAX) - final Deadline nextDeadline = this.idleTimeoutEvent.nextDeadline; - if (!nextDeadline.equals(Deadline.MAX)) { - this.idleTimeoutEvent.nextDeadline = Deadline.MAX; - endpoint.timer().reschedule(this.idleTimeoutEvent, Deadline.MIN); - } + // disable the idle timeout timer event + disableTimedEvent(endpoint.timer(), this.idleTimeoutEvent); this.idleTimeoutEvent = null; } private void startStreamDataBlockedTimer() { assert stateLock.isHeldByCurrentThread() : "not holding state lock"; - // 75% of idle timeout or if idle timeout is not configured, then 30 seconds + // 75% of QUIC idle timeout or if QUIC idle timeout is not configured, then 30 seconds final long timeoutMillis = getIdleTimeout() .map((v) -> (long) (0.75 * v)) .orElse(30000L); @@ -194,22 +194,95 @@ final class IdleTimeoutManager { } final QuicEndpoint endpoint = this.connection.endpoint(); assert endpoint != null : "QUIC endpoint is null"; - // disable the event (refreshDeadline() of StreamDataBlockedEvent will return Deadline.MAX) - final Deadline nextDeadline = this.streamDataBlockedEvent.nextDeadline; - if (!nextDeadline.equals(Deadline.MAX)) { - this.streamDataBlockedEvent.nextDeadline = Deadline.MAX; - endpoint.timer().reschedule(this.streamDataBlockedEvent, Deadline.MIN); - } + // disable the stream data blocked timer event + disableTimedEvent(endpoint.timer(), this.streamDataBlockedEvent); this.streamDataBlockedEvent = null; } + // set up a PING timer if the application layer's max idle duration for the connection + // is larger than that of the negotiated QUIC idle timeout for that connection + void appLayerMaxIdle(final Duration maxIdle, final Supplier trafficGenerationCheck) { + Objects.requireNonNull(maxIdle, "maxIdle"); + Objects.requireNonNull(trafficGenerationCheck, "trafficGenerationCheck"); + if (maxIdle.isZero() || maxIdle.isNegative()) { + throw new IllegalArgumentException("invalid maxIdle duration: " + maxIdle); + } + // the application layer must not configure its max idle duration + // until the QUIC connection's handshake has successfully completed + requireSuccessfulHandshake(); + + if (!this.trafficGenerationCheck.compareAndSet(null, trafficGenerationCheck)) { + throw new IllegalStateException("app layer max inactivity already set"); + } + final Optional quicIdleTimeout = getIdleTimeout(); + if (quicIdleTimeout.isEmpty()) { + // the QUIC connection will never idle timeout, nothing more to do + return; + } + // we start the PING sending timer event only if the QUIC layer idle timeout + // is lesser than the app layer's desired idle time + if (Duration.ofMillis(quicIdleTimeout.get()).compareTo(maxIdle) < 0) { + this.stateLock.lock(); + try { + if (shutdown.get()) { + return; + } + // QUIC connection has a lower idle timeout than the app layer. start a timer + // which checks with the app layer at regular intervals to decide whether to + // send a PING to keep the QUIC connection active. + startPingTimer(); + } finally { + this.stateLock.unlock(); + } + } + } + + private void startPingTimer() { + assert stateLock.isHeldByCurrentThread() : "not holding state lock"; + // we don't expect the timer to be started more than once + assert this.pingEvent == null : "PING timer already started"; + final Optional quicIdleTimeout = getIdleTimeout(); + assert quicIdleTimeout.isPresent() : "QUIC idle timeout is disabled, no need to start PING timer"; + // potential PING generation every 75% of QUIC idle timeout + final long pingFrequencyMillis = (long) (0.75 * quicIdleTimeout.get()); + assert pingFrequencyMillis > 0 : "unexpected ping frequency: " + pingFrequencyMillis; + final QuicTimerQueue timerQueue = connection.endpoint().timer(); + final Deadline deadline = timeLine().instant().plusMillis(pingFrequencyMillis); + // create the timeout event and register with the QuicTimerQueue. + this.pingEvent = new PingEvent(deadline, pingFrequencyMillis); + timerQueue.offer(this.pingEvent); + if (debug.on()) { + debug.log("started periodic PING for connection," + + " ping event: " + this.pingEvent + + " deadline: " + deadline); + } else { + Log.logQuic("{0} started periodic PING for connection," + + " ping event: {1} deadline: {2}", + connection.logTag(), this.pingEvent, deadline); + } + } + + private void stopPingTimer() { + assert stateLock.isHeldByCurrentThread() : "not holding state lock"; + if (this.pingEvent == null) { + return; + } + final QuicEndpoint endpoint = this.connection.endpoint(); + assert endpoint != null : "QUIC endpoint is null"; + // disable the ping timer event + disableTimedEvent(endpoint.timer(), this.pingEvent); + this.pingEvent = null; + this.trafficGenerationCheck.set(null); + } + + /** * Attempts to notify the idle connection management that this connection should * be considered "in use". This way the idle connection management doesn't close * this connection during the time the connection is handed out from the pool and any * new stream created on that connection. * - * @return true if the connection has been successfully reserved and is {@link #isOpen()}. false + * @return true if the connection has been successfully reserved. false * otherwise; in which case the connection must not be handed out from the pool. */ boolean tryReserveForUse() { @@ -221,7 +294,7 @@ final class IdleTimeoutManager { } // if the connection is nearing idle timeout due to lack of traffic then // don't use it - final long lastPktActivity = lastPacketActivityAt; + final long lastPktActivity = lastPacketActivityNanos; final long currentNanos = System.nanoTime(); final long inactivityMs = MILLISECONDS.convert((currentNanos - lastPktActivity), NANOSECONDS); @@ -232,7 +305,7 @@ final class IdleTimeoutManager { return false; } // express interest in using the connection - this.lastUsageReservationAt = System.nanoTime(); + this.lastUsageReservationNanos = System.nanoTime(); return true; } finally { this.idleTerminationLock.unlock(); @@ -256,8 +329,9 @@ final class IdleTimeoutManager { return val == NO_IDLE_TIMEOUT ? Optional.empty() : Optional.of(val); } - void keepAlive() { - lastPacketActivityAt = System.nanoTime(); // TODO: timeline().instant()? + // consider the connection as active as of this moment + void markActive() { + lastPacketActivityNanos = System.nanoTime(); // TODO: timeline().instant()? } void shutdown() { @@ -270,6 +344,7 @@ final class IdleTimeoutManager { // unregister the timeout events from the QuicTimerQueue stopIdleTerminationTimer(); stopStreamDataBlockedTimer(); + stopPingTimer(); } finally { this.stateLock.unlock(); } @@ -318,6 +393,15 @@ final class IdleTimeoutManager { return this.connection.endpoint().timeSource(); } + private static void disableTimedEvent(final QuicTimerQueue timer, final TimedEvent te) { + // disable the event (refreshDeadline() of TimedEvent will return Deadline.MAX) + final Deadline nextDeadline = te.nextDeadline; + if (!nextDeadline.equals(Deadline.MAX)) { + te.nextDeadline = Deadline.MAX; + timer.reschedule(te, Deadline.MIN); + } + } + // called when the connection has been idle past its idle timeout duration private void idleTimedOut() { if (shutdown.get()) { @@ -346,41 +430,59 @@ final class IdleTimeoutManager { } } // silently close the connection and discard all its state - final TerminationCause cause = forSilentTermination("connection idle timed out (" - + timeoutMillis + " milli seconds)"); + var type = connection.isClientConnection() ? "client" : "server"; + var label = "quic:" + connection.uniqueId(); + final TerminationCause cause = forSilentTermination(type + " connection idle timed out (" + + timeoutMillis + " milli seconds) on " + label); connection.terminator.terminate(cause); } private long computeInactivityMillis() { + assert idleTerminationLock.isHeldByCurrentThread() : "not holding idle termination lock"; final long currentNanos = System.nanoTime(); - final long lastActiveNanos = Math.max(lastPacketActivityAt, lastUsageReservationAt); + final long lastActiveNanos = Math.max(lastPacketActivityNanos, lastUsageReservationNanos); return MILLISECONDS.convert((currentNanos - lastActiveNanos), NANOSECONDS); } - final class IdleTimeoutEvent implements QuicTimedEvent { - private final long eventId; - private volatile Deadline deadline; - private volatile Deadline nextDeadline; + sealed abstract class TimedEvent implements QuicTimedEvent { + protected final long eventId; + protected volatile Deadline deadline; + protected volatile Deadline nextDeadline; - private IdleTimeoutEvent(final Deadline deadline) { + private TimedEvent(final Deadline deadline) { assert deadline != null : "timeout deadline is null"; this.deadline = this.nextDeadline = deadline; this.eventId = QuicTimerQueue.newEventId(); } @Override - public Deadline deadline() { + public final Deadline deadline() { return this.deadline; } @Override - public Deadline refreshDeadline() { + public final Deadline refreshDeadline() { if (shutdown.get()) { return this.deadline = this.nextDeadline = Deadline.MAX; } return this.deadline = this.nextDeadline; } + @Override + public final long eventId() { + return this.eventId; + } + + @Override + public abstract Deadline handle(); + } + + final class IdleTimeoutEvent extends TimedEvent { + + private IdleTimeoutEvent(final Deadline deadline) { + super(deadline); + } + @Override public Deadline handle() { if (shutdown.get()) { @@ -440,41 +542,18 @@ final class IdleTimeoutManager { } } - @Override - public long eventId() { - return this.eventId; - } - @Override public String toString() { return "QuicIdleTimeoutEvent-" + this.eventId; } } - final class StreamDataBlockedEvent implements QuicTimedEvent { - private final long eventId; + final class StreamDataBlockedEvent extends TimedEvent { private final long timeoutMillis; - private volatile Deadline deadline; - private volatile Deadline nextDeadline; private StreamDataBlockedEvent(final Deadline deadline, final long timeoutMillis) { - assert deadline != null : "timeout deadline is null"; - this.deadline = this.nextDeadline = deadline; + super(deadline); this.timeoutMillis = timeoutMillis; - this.eventId = QuicTimerQueue.newEventId(); - } - - @Override - public Deadline deadline() { - return this.deadline; - } - - @Override - public Deadline refreshDeadline() { - if (shutdown.get()) { - return this.deadline = this.nextDeadline = Deadline.MAX; - } - return this.deadline = this.nextDeadline; } @Override @@ -515,14 +594,95 @@ final class IdleTimeoutManager { } } - @Override - public long eventId() { - return this.eventId; - } - @Override public String toString() { return "StreamDataBlockedEvent-" + this.eventId; } } + + + final class PingEvent extends TimedEvent { + private final long pingFrequencyNanos; + private final long idleTimeoutNanos; + + private PingEvent(final Deadline deadline, final long pingFrequencyMillis) { + super(deadline); + this.pingFrequencyNanos = MILLISECONDS.toNanos(pingFrequencyMillis); + if (this.pingFrequencyNanos <= 0) { + throw new IllegalArgumentException("ping frequency is too small: " + + pingFrequencyMillis + " milliseconds"); + } + this.idleTimeoutNanos = MILLISECONDS.toNanos(getIdleTimeout().get()); + } + + @Override + public Deadline handle() { + if (shutdown.get()) { + // timeout manager is shutdown, nothing more to do + return this.nextDeadline = Deadline.MAX; + } + if (!shouldInitiateAppLayerCheck()) { + // reschedule for next round + this.nextDeadline = timeLine().instant().plusNanos(this.pingFrequencyNanos); + return this.nextDeadline; + } + // check with the app layer if traffic generation is required + final Supplier check = trafficGenerationCheck.get(); + if (check == null) { + // generateTrafficCheck can be null if the timeout manager was shutdown + // when this event handling was in progress. don't send a PING frame + // in that case. + assert shutdown.get() : "trafficGenerationCheck is absent"; + return this.nextDeadline = Deadline.MAX; + } + if (check.get()) { + // app layer OKed sending a PING + connection.requestSendPing(); + if (debug.on()) { + debug.log("enqueued a PING frame"); + } else { + Log.logQuic("{0} enqueued a PING frame", connection.logTag()); + } + } else { + // app layer told us not to send a PING. + // we skip the PING generation only for the current round, no need + // to disable future PING checks + if (debug.on()) { + debug.log("skipping PING generation"); + } else { + Log.logQuic("{0} skipping PING generation", connection.logTag()); + } + } + this.nextDeadline = timeLine().instant().plusNanos(this.pingFrequencyNanos); + return this.nextDeadline; + } + + @Override + public String toString() { + return "PingEvent-" + this.eventId; + } + + // returns true if the app layer traffic generation check needs to be invoked, + // false otherwise. + private boolean shouldInitiateAppLayerCheck() { + final long lastPktAt = lastPacketActivityNanos; + final long now = System.nanoTime(); + if ((now - lastPktAt) >= this.pingFrequencyNanos) { + // no traffic during the ping interval, initiate a app layer check + // to see if explicit traffic needs to be generated + return true; + } + // check if the connection will potentially idle terminate before the next + // ping check is scheduled, if yes, then initiate a app layer traffic + // generation check now + final long idleTerminationAt = lastPktAt + this.idleTimeoutNanos; + final long nextPingCheck = now + this.pingFrequencyNanos; + if (idleTerminationAt - nextPingCheck <= 0) { + return true; + } + // connection appears to be receiving traffic, no need to initiate app layer + // traffic generation check + return false; + } + } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/PacketSpaceManager.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/PacketSpaceManager.java index 494af85447e..487a8a186f6 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/PacketSpaceManager.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/PacketSpaceManager.java @@ -97,6 +97,7 @@ public sealed class PacketSpaceManager implements PacketSpace private final QuicCongestionController congestionController; private volatile boolean blockedByCC; + private volatile boolean blockedByPacer; // packet threshold for loss detection; RFC 9002 suggests 3 private static final long kPacketThreshold = 3; // Multiplier for persistent congestion; RFC 9002 suggests 3 @@ -384,9 +385,10 @@ public sealed class PacketSpaceManager implements PacketSpace } packetEmitter.checkAbort(PacketSpaceManager.this.packetNumberSpace); // Handle is called from within the executor - var nextDeadline = this.nextDeadline; + Deadline newDeadline; Deadline now = now(); do { + congestionController.updatePacer(now); transmitNow = false; var closed = !isOpenForTransmission(); if (closed) { @@ -404,6 +406,7 @@ public sealed class PacketSpaceManager implements PacketSpace boolean needBackoff = isPTO(now); int packetsSent = 0; boolean cwndAvailable; + long startTime = System.nanoTime(); while ((cwndAvailable = congestionController.canSendPacket()) || (needBackoff && packetsSent < 2)) { // if PTO, try to send 2 packets if (!isOpenForTransmission()) { @@ -442,6 +445,7 @@ public sealed class PacketSpaceManager implements PacketSpace + qkue.getMessage()); } if (!sentNew) { + congestionController.appLimited(); break; } else { if (needBackoff && packetsSent == 0 && Log.quicRetransmit()) { @@ -451,12 +455,19 @@ public sealed class PacketSpaceManager implements PacketSpace } packetsSent++; } - blockedByCC = !cwndAvailable; + if (packetsSent != 0 && Log.quicCC()) { + Log.logQuic("%s OUT: sent: %s packets in %s ns, cwnd limited: %s, pacer limited: %s".formatted( + packetEmitter.logTag(), packetsSent, System.nanoTime() - startTime, + congestionController.isCwndLimited(), congestionController.isPacerLimited())); + } + blockedByCC = !cwndAvailable && congestionController.isCwndLimited(); + blockedByPacer = !cwndAvailable && congestionController.isPacerLimited(); if (!cwndAvailable && isOpenForTransmission()) { if (debug.on()) debug.log("handle: blocked by CC"); // CC might be available already if (congestionController.canSendPacket()) { if (debug.on()) debug.log("handle: unblocked immediately"); + blockedByCC = blockedByPacer = false; transmitNow = true; } } @@ -523,16 +534,17 @@ public sealed class PacketSpaceManager implements PacketSpace packetEmitter.ptoBackoffIncreased(PacketSpaceManager.this, backoff); } - // if nextDeadline is not Deadline.MAX the task will be + // if newDeadline is not Deadline.MAX the task will be // automatically rescheduled. if (debug.on()) debug.log("handle: refreshing deadline"); - nextDeadline = computeNextDeadline(); - } while(!nextDeadline.isAfter(now)); + newDeadline = computeNextDeadline(); + now = now(); + } while(!newDeadline.isAfter(now)); - logNoDeadline(nextDeadline, true); - if (Deadline.MAX.equals(nextDeadline)) return; + logNoDeadline(newDeadline, true); + if (Deadline.MAX.equals(newDeadline)) return; // we have a new deadline - packetEmitter.reschedule(this, nextDeadline); + packetEmitter.reschedule(this, newDeadline); } /** @@ -1389,6 +1401,15 @@ public sealed class PacketSpaceManager implements PacketSpace Deadline ackDeadline = (ack == null || ack.sent() != null) ? Deadline.MAX // if the ack frame has already been sent, getNextAck() returns null : ack.deadline(); + if (blockedByPacer) { + Deadline pacerDeadline = congestionController.pacerDeadline(); + if (verbose && Log.quicTimer()) { + Log.logQuic(String.format("%s: [%s] pacer deadline: %s, ackDeadline: %s, deadline in %s", + packetEmitter.logTag(), packetNumberSpace, pacerDeadline, ackDeadline, + Utils.debugDeadline(now(), min(ackDeadline, pacerDeadline)))); + } + return min(ackDeadline, pacerDeadline); + } Deadline lossDeadline = getLossTimer(); // TODO: consider removing the debug traces in this method when integrating // if both loss deadline and PTO timer are set, loss deadline is always earlier diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicBaseCongestionController.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicBaseCongestionController.java new file mode 100644 index 00000000000..7dd3276f0d3 --- /dev/null +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicBaseCongestionController.java @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2022, 2025, 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 jdk.internal.net.http.quic; + +import jdk.internal.net.http.common.Deadline; +import jdk.internal.net.http.common.Log; +import jdk.internal.net.http.common.TimeLine; +import jdk.internal.net.http.common.TimeSource; +import jdk.internal.net.http.common.Utils; +import jdk.internal.net.http.quic.frames.AckFrame; +import jdk.internal.net.http.quic.packets.QuicPacket; + +import java.util.Collection; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Implementation of the common parts of a QUIC congestion controller based on RFC 9002. + * + * This class implements the common parts of a congestion controller: + * - slow start + * - loss recovery + * - cooperation with pacer + * + * Subclasses implement congestion window growth in congestion avoidance phase. + * + * @spec https://www.rfc-editor.org/info/rfc9002 + * RFC 9002: QUIC Loss Detection and Congestion Control + */ +abstract class QuicBaseCongestionController implements QuicCongestionController { + // higher of 14720 and 2*maxDatagramSize; we use fixed maxDatagramSize + private static final int INITIAL_WINDOW = Math.max(14720, 2 * QuicConnectionImpl.DEFAULT_DATAGRAM_SIZE); + private static final int MAX_BYTES_IN_FLIGHT = Math.clamp( + Utils.getLongProperty("jdk.httpclient.quic.maxBytesInFlight", 1 << 24), + 1 << 14, 1 << 24); + final TimeLine timeSource; + final String dbgTag; + final Lock lock = new ReentrantLock(); + long congestionWindow = INITIAL_WINDOW; + int maxDatagramSize = QuicConnectionImpl.DEFAULT_DATAGRAM_SIZE; + int minimumWindow = 2 * maxDatagramSize; + long bytesInFlight; + // maximum bytes in flight seen since the last congestion event + long maxBytesInFlight; + Deadline congestionRecoveryStartTime; + long ssThresh = Long.MAX_VALUE; + + private final QuicPacer pacer; + + QuicBaseCongestionController(String dbgTag, QuicRttEstimator rttEstimator) { + this(dbgTag, TimeSource.source(), rttEstimator); + } + + // Allows to pass a custom timeline for testing + QuicBaseCongestionController(String dbgTag, TimeLine source, QuicRttEstimator rttEstimator) { + this.dbgTag = dbgTag; + this.timeSource = source; + this.pacer = new QuicPacer(rttEstimator, this); + } + + boolean inCongestionRecovery(Deadline sentTime) { + return (congestionRecoveryStartTime != null && + !sentTime.isAfter(congestionRecoveryStartTime)); + } + + abstract void onCongestionEvent(Deadline sentTime); + + private static boolean inFlight(QuicPacket packet) { + // packet is in flight if it contains anything other than a single ACK frame + // specifically, a packet containing padding is considered to be in flight. + return packet.frames().size() != 1 || + !(packet.frames().get(0) instanceof AckFrame); + } + + @Override + public boolean canSendPacket() { + lock.lock(); + try { + if (bytesInFlight >= MAX_BYTES_IN_FLIGHT) { + return false; + } + if (isCwndLimited() || isPacerLimited()) { + return false; + } + return true; + } finally { + lock.unlock(); + } + } + + @Override + public void updateMaxDatagramSize(int newSize) { + lock.lock(); + try { + if (minimumWindow != newSize * 2) { + minimumWindow = newSize * 2; + maxDatagramSize = newSize; + congestionWindow = Math.max(congestionWindow, minimumWindow); + } + } finally { + lock.unlock(); + } + } + + @Override + public void packetSent(int packetBytes) { + lock.lock(); + try { + bytesInFlight += packetBytes; + if (bytesInFlight > maxBytesInFlight) { + maxBytesInFlight = bytesInFlight; + } + pacer.packetSent(packetBytes); + } finally { + lock.unlock(); + } + } + + @Override + public void packetAcked(int packetBytes, Deadline sentTime) { + lock.lock(); + try { + long oldWindow = congestionWindow; + assert oldWindow >= minimumWindow : + "Congestion window lower than minimum: %s < %s".formatted(oldWindow, minimumWindow); + bytesInFlight -= packetBytes; + // RFC 9002 says we should not increase cwnd when application limited. + // The concept itself is poorly defined. + // Here we limit cwnd growth based on the maximum bytes in flight + // observed since the last congestion event + if (inCongestionRecovery(sentTime)) { + if (Log.quicCC() && Log.trace()) { + Log.logQuic(dbgTag + " Acked, in recovery: bytes: " + packetBytes + + ", in flight: " + bytesInFlight); + } + return; + } + boolean isAppLimited; + if (congestionWindow < ssThresh) { + isAppLimited = congestionWindow >= 2 * maxBytesInFlight; + if (!isAppLimited) { + congestionWindow += packetBytes; + } + } else { + isAppLimited = congestionAvoidanceAcked(packetBytes, sentTime); + } + if (Log.quicCC() && Log.trace()) { + if (isAppLimited) { + Log.logQuic(dbgTag + " Acked, not blocked: bytes: " + packetBytes + + ", in flight: " + bytesInFlight); + } else { + Log.logQuic(dbgTag + " Acked, increased: bytes: " + packetBytes + + ", in flight: " + bytesInFlight + + ", new cwnd:" + congestionWindow); + } + } + assert congestionWindow >= oldWindow : + "Window size decreased on ACK: %s to %s".formatted(oldWindow, congestionWindow); + } finally { + lock.unlock(); + } + } + + abstract boolean congestionAvoidanceAcked(int packetBytes, Deadline sentTime); + + @Override + public void packetLost(Collection lostPackets, Deadline sentTime, boolean persistent) { + lock.lock(); + try { + for (QuicPacket packet : lostPackets) { + if (inFlight(packet)) { + bytesInFlight -= packet.size(); + } + } + onCongestionEvent(sentTime); + if (persistent) { + congestionWindow = minimumWindow; + congestionRecoveryStartTime = null; + if (Log.quicCC()) { + Log.logQuic(dbgTag + " Persistent congestion: ssThresh: " + ssThresh + + ", in flight: " + bytesInFlight + + ", cwnd:" + congestionWindow); + } + } + assert congestionWindow >= minimumWindow : + "Congestion window lower than minimum: %s < %s".formatted(congestionWindow, minimumWindow); + } finally { + lock.unlock(); + } + } + + @Override + public void packetDiscarded(Collection discardedPackets) { + lock.lock(); + try { + for (QuicPacket packet : discardedPackets) { + if (inFlight(packet)) { + bytesInFlight -= packet.size(); + } + } + } finally { + lock.unlock(); + } + } + + @Override + public long congestionWindow() { + lock.lock(); + try { + return congestionWindow; + } finally { + lock.unlock(); + } + } + + @Override + public long initialWindow() { + lock.lock(); + try { + return Math.max(14720, 2 * maxDatagramSize); + } finally { + lock.unlock(); + } + } + + @Override + public long maxDatagramSize() { + lock.lock(); + try { + return maxDatagramSize; + } finally { + lock.unlock(); + } + } + + @Override + public boolean isSlowStart() { + lock.lock(); + try { + return congestionWindow < ssThresh; + } finally { + lock.unlock(); + } + } + + @Override + public void updatePacer(Deadline now) { + lock.lock(); + try { + pacer.updateQuota(now); + } finally { + lock.unlock(); + } + } + + @Override + public boolean isPacerLimited() { + lock.lock(); + try { + return !pacer.canSend(); + } finally { + lock.unlock(); + } + } + + @Override + public boolean isCwndLimited() { + lock.lock(); + try { + return congestionWindow - bytesInFlight < maxDatagramSize; + } finally { + lock.unlock(); + } + } + + @Override + public Deadline pacerDeadline() { + lock.lock(); + try { + return pacer.twoPacketDeadline(); + } finally { + lock.unlock(); + } + } + + @Override + public void appLimited() { + lock.lock(); + try { + pacer.appLimited(); + } finally { + lock.unlock(); + } + } +} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicCongestionController.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicCongestionController.java index 4bfad2c5560..94dafaf16eb 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicCongestionController.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicCongestionController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -72,4 +72,49 @@ public interface QuicCongestionController { */ void packetDiscarded(Collection discardedPackets); + /** + * {@return the current size of the congestion window in bytes} + */ + long congestionWindow(); + + /** + * {@return the initial window size in bytes} + */ + long initialWindow(); + + /** + * {@return maximum datagram size} + */ + long maxDatagramSize(); + + /** + * {@return true if the connection is in slow start phase} + */ + boolean isSlowStart(); + + /** + * Update the pacer with the current time + * @param now the current time + */ + void updatePacer(Deadline now); + + /** + * {@return true if sending is blocked by pacer} + */ + boolean isPacerLimited(); + + /** + * {@return true if sending is blocked by congestion window} + */ + boolean isCwndLimited(); + + /** + * {@return deadline when pacer will unblock sending} + */ + Deadline pacerDeadline(); + + /** + * Notify the congestion controller that sending is app-limited + */ + void appLimited(); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java index 9a280c3a8a5..c07df1c6eb2 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java @@ -174,17 +174,29 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece public static final int SMALLEST_MAXIMUM_DATAGRAM_SIZE = QuicClient.SMALLEST_MAXIMUM_DATAGRAM_SIZE; + // The default value for the Quic maxInitialTimeout, in seconds. Will be clamped to [1, Integer.MAX_vALUE] public static final int DEFAULT_MAX_INITIAL_TIMEOUT = Math.clamp( Utils.getIntegerProperty("jdk.httpclient.quic.maxInitialTimeout", 30), 1, Integer.MAX_VALUE); + // The default value for the initial_max_data transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final long DEFAULT_INITIAL_MAX_DATA = Math.clamp( Utils.getLongProperty("jdk.httpclient.quic.maxInitialData", 15 << 20), 0, 1L << 60); + // The default value for the initial_max_stream_data_bidi_local, initial_max_stream_data_bidi_remote, + // and initial_max_stream_data_uni transport parameters that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final long DEFAULT_INITIAL_STREAM_MAX_DATA = Math.clamp( Utils.getIntegerProperty("jdk.httpclient.quic.maxStreamInitialData", 6 << 20), 0, 1L << 60); + // The default value for the initial_max_streams_bidi transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. + // The Http3ClientImpl typically provides a value of 0, so this property has no effect + // on QuicConnectionImpl instances created on behalf of the HTTP/3 client public static final int DEFAULT_MAX_BIDI_STREAMS = - Utils.getIntegerProperty("jdk.httpclient.quic.maxBidiStreams", 100); + Utils.getIntegerProperty("jdk.internal.httpclient.quic.maxBidiStreams", 100); + // The default value for the initial_max_streams_uni transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final int DEFAULT_MAX_UNI_STREAMS = Utils.getIntegerProperty("jdk.httpclient.quic.maxUniStreams", 100); public static final boolean USE_DIRECT_BUFFER_POOL = Utils.getBooleanProperty( @@ -334,7 +346,7 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece this.connectionId = this.endpoint.idFactory().newConnectionId(); this.logTag = logTagFormat.formatted(labelId); this.dbgTag = dbgTag(quicInstance, logTag); - this.congestionController = new QuicRenoCongestionController(dbgTag); + this.congestionController = createCongestionController(dbgTag, rttEstimator); this.originalVersion = this.quicVersion = firstFlightVersion == null ? QuicVersion.firstFlightVersion(quicInstance.getAvailableVersions()) : firstFlightVersion; @@ -366,6 +378,16 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece if (debug.on()) debug.log("Quic Connection Created"); } + private static QuicCongestionController createCongestionController + (String dbgTag, QuicRttEstimator rttEstimator) { + String algo = System.getProperty("jdk.internal.httpclient.quic.congestionController", "cubic"); + if (algo.equalsIgnoreCase("reno")) { + return new QuicRenoCongestionController(dbgTag, rttEstimator); + } else { + return new QuicCubicCongestionController(dbgTag, rttEstimator); + } + } + @Override public final long uniqueId() { return labelId; @@ -1977,7 +1999,7 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece case NONE -> throw new InternalError("Unrecognized packet type"); } // packet has been processed successfully - connection isn't idle (RFC-9000, section 10.1) - this.terminator.keepAlive(); + this.terminator.markActive(); if (packetSpace != null) { packetSpace.packetReceived( packetType, @@ -2809,7 +2831,7 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece // RFC-9000, section 10.1: An endpoint also restarts its idle timer when sending // an ack-eliciting packet ... if (packet.isAckEliciting()) { - this.terminator.keepAlive(); + this.terminator.markActive(); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicCubicCongestionController.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicCubicCongestionController.java new file mode 100644 index 00000000000..a7a1cd0c0bc --- /dev/null +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicCubicCongestionController.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2022, 2025, 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 jdk.internal.net.http.quic; + +import jdk.internal.net.http.common.Deadline; +import jdk.internal.net.http.common.Log; +import jdk.internal.net.http.common.TimeLine; + +import java.util.concurrent.TimeUnit; + +/** + * Implementation of the CUBIC congestion controller + * based on RFC 9438. + * + * @spec https://www.rfc-editor.org/rfc/rfc9438.html + * RFC 9438: CUBIC for Fast and Long-Distance Networks + */ +public final class QuicCubicCongestionController extends QuicBaseCongestionController { + + public static final double BETA = 0.7; + public static final double ALPHA = 3 * (1 - BETA) / (1 + BETA); + private static final double C = 0.4; + private final QuicRttEstimator rttEstimator; + // Cubic curve inflection point, in bytes + private long wMaxBytes; + // cwnd before the most recent congestion event + private long cwndPriorBytes; + // "t" from RFC 9438 + private long timeNanos; + // "K" from RFC 9438 + private long kNanos; + // estimate for the Reno-friendly congestion window + private long wEstBytes; + // the most recent time when the congestion window was filled + private Deadline lastFullWindow; + + public QuicCubicCongestionController(String dbgTag, QuicRttEstimator rttEstimator) { + super(dbgTag, rttEstimator); + this.rttEstimator = rttEstimator; + } + + // for testing + public QuicCubicCongestionController(TimeLine source, QuicRttEstimator rttEstimator) { + super("TEST", source, rttEstimator); + this.rttEstimator = rttEstimator; + } + + @Override + public void packetSent(int packetBytes) { + lock.lock(); + try { + super.packetSent(packetBytes); + if (isCwndLimited()) { + Deadline now = timeSource.instant(); + if (lastFullWindow == null) { + lastFullWindow = now; + } else { + long timePassedNanos = Deadline.between(lastFullWindow, now).toNanos(); + if (timePassedNanos > 0) { + /* "The elapsed time MUST NOT include periods during which cwnd + has not been updated due to application-limited behavior" + "A flow is application limited if it is currently sending less + than what is allowed by the congestion window." + + We are sending asynchronously; one thread is sending data, + a separate thread is processing the acknowledgements. + We can't rely on cwnd being fully utilized when we process an ack, because + most of the time it won't be. + + Instead, we assume that if we filled the cwnd, we were not application-limited + in the last RTT (which is a pretty good approximation because of pacing), + and acknowledgements for all packets sent prior to filling the cwnd + count towards cwnd increase. + */ + long rttNanos = TimeUnit.MICROSECONDS.toNanos(rttEstimator.state().smoothedRttMicros()); + timeNanos += Math.min(timePassedNanos, rttNanos); + lastFullWindow = now; + } + } + } + } finally { + lock.unlock(); + } + } + + + boolean congestionAvoidanceAcked(int packetBytes, Deadline sentTime) { + boolean isAppLimited = sentTime.isAfter(lastFullWindow); + if (!isAppLimited) { + if (wEstBytes < cwndPriorBytes) { + wEstBytes += Math.max((long) (ALPHA * maxDatagramSize * packetBytes / congestionWindow), 1); + } else { + wEstBytes += Math.max((long)maxDatagramSize * packetBytes / congestionWindow, 1); + } + // target = Wcubic(t + RTT) + long rttNanos = TimeUnit.MICROSECONDS.toNanos(rttEstimator.state().smoothedRttMicros()); + double dblTargetBytes = wCubicBytes(timeNanos + rttNanos); + assert dblTargetBytes > 0 : "Unexpected negative target bytes"; + long targetBytes = (long) Math.min(dblTargetBytes, 1.5 * congestionWindow); + if (targetBytes > congestionWindow) { + long oldWindow = congestionWindow; + congestionWindow += Math.max((targetBytes - congestionWindow) * packetBytes / congestionWindow, 1L); + assert congestionWindow > oldWindow : + "Window size decreased: %s to %s".formatted(oldWindow, congestionWindow); + } + if (wEstBytes > congestionWindow) { + congestionWindow = wEstBytes; + } + } + return isAppLimited; + } + + // Wcubic(t) = C * (t-K [seconds])^3 + Wmax (segments) + private double wCubicBytes(long timeNanos) { + return (C * maxDatagramSize * Math.pow((timeNanos - kNanos) / 1e9, 3)) + wMaxBytes; + } + + void onCongestionEvent(Deadline sentTime) { + if (inCongestionRecovery(sentTime)) { + return; + } + if (congestionWindow < wMaxBytes) { + // fast convergence + wMaxBytes = (long) ((1 + BETA) * congestionWindow / 2); + } else { + wMaxBytes = congestionWindow; + } + cwndPriorBytes = congestionWindow; + congestionRecoveryStartTime = timeSource.instant(); + ssThresh = (long)(congestionWindow * BETA); + wEstBytes = congestionWindow = Math.max(minimumWindow, ssThresh); + maxBytesInFlight = 0; + timeNanos = 0; + // set lastFullWindow to prevent rapid timeNanos growth + lastFullWindow = congestionRecoveryStartTime; + // ((wmax_segments - cwnd_segments) / C) ^ (1/3) seconds + kNanos = (long)(Math.cbrt((wMaxBytes - congestionWindow) / C / maxDatagramSize) * 1_000_000_000); + // kNanos may be negative if we reduced the window below minimum, + // and fast convergence was used. This is acceptable. + if (Log.quicCC()) { + Log.logQuic(dbgTag + " Congestion: ssThresh: " + ssThresh + + ", in flight: " + bytesInFlight + + ", cwnd:" + congestionWindow + + ", K: " + TimeUnit.NANOSECONDS.toMillis(kNanos) + " ms"); + } + } +} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java index d9bf5fe6dcf..b1de5ef4bfd 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java @@ -62,6 +62,7 @@ import jdk.internal.net.http.common.SequentialScheduler; import jdk.internal.net.http.common.TimeLine; import jdk.internal.net.http.common.TimeSource; import jdk.internal.net.http.common.Utils; +import jdk.internal.net.http.common.Utils.UseVTForSelector; import jdk.internal.net.http.quic.QuicSelector.QuicNioSelector; import jdk.internal.net.http.quic.QuicSelector.QuicVirtualThreadPoller; import jdk.internal.net.http.quic.packets.QuicPacket.HeadersType; @@ -116,7 +117,6 @@ public abstract sealed class QuicEndpoint implements AutoCloseable static final boolean DGRAM_SEND_ASYNC; static final int MAX_BUFFERED_HIGH; static final int MAX_BUFFERED_LOW; - enum UseVTForSelector { ALWAYS, NEVER, DEFAULT } static final UseVTForSelector USE_VT_FOR_SELECTOR; static { // This default value is the maximum payload size of @@ -144,11 +144,8 @@ public abstract sealed class QuicEndpoint implements AutoCloseable if (maxBufferLow >= maxBufferHigh) maxBufferLow = maxBufferHigh >> 1; MAX_BUFFERED_HIGH = maxBufferHigh; MAX_BUFFERED_LOW = maxBufferLow; - String useVtForSelector = - System.getProperty("jdk.internal.httpclient.quic.selector.useVirtualThreads", "default"); - USE_VT_FOR_SELECTOR = Stream.of(UseVTForSelector.values()) - .filter((v) -> v.name().equalsIgnoreCase(useVtForSelector)) - .findFirst().orElse(UseVTForSelector.DEFAULT); + var property = "jdk.internal.httpclient.quic.selector.useVirtualThreads"; + USE_VT_FOR_SELECTOR = Utils.useVTForSelector(property, "default"); } /** diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicPacer.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicPacer.java new file mode 100644 index 00000000000..50d8485785f --- /dev/null +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicPacer.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2025, 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 jdk.internal.net.http.quic; + +import jdk.internal.net.http.common.Deadline; +import jdk.internal.net.http.common.Log; +import jdk.internal.net.http.common.Utils; +import jdk.internal.util.OperatingSystem; + +import java.time.temporal.ChronoUnit; +import java.util.concurrent.TimeUnit; + +/** + * Implementation of pacing. + * + * When the connection is sending at a rate lower than permitted + * by the congestion controller, pacer is responsible for spreading out + * the outgoing packets across the entire RTT. + * + * Technically the pacer provides two functions: + * - computes the number of packets that can be sent now + * - computes the time when another packet can be sent + * + * When a new flow starts, or when the flow is not pacer-limited, + * the pacer limits the window to: + * max(INITIAL_WINDOW, pacingRate / timerFreq) + * timerFreq is the best timer resolution we can get from the selector. + * pacingRate is N * congestionWindow / smoothedRTT + * where N = 2 when in slow start, N = 1.25 otherwise. + * + * After that, the window refills at pacingRate, up to two timer periods or 4 packets, + * whichever is higher. + * + * The time when another packet can be sent is computed + * as the time when the window will allow at least 2 packets. + * + * All methods are externally synchronized in congestion controller. + * + * Ideas taken from: + * https://www.rfc-editor.org/rfc/rfc9002.html#name-pacing + * https://www.ietf.org/archive/id/draft-welzl-iccrg-pacing-03.html + */ +public class QuicPacer { + + // usually 64 Hz on Windows, 1000 on Linux + private static final long DEFAULT_TIMER_FREQ_HZ = OperatingSystem.isWindows() ? 64 : 1000; + private static final long TIMER_FREQ_HZ = Math.clamp( + Utils.getLongProperty("jdk.httpclient.quic.timerFrequency", DEFAULT_TIMER_FREQ_HZ), + 1, 1000); + + private final QuicRttEstimator rttEstimator; + private final QuicCongestionController congestionController; + + private boolean appLimited; + private long quota; + private Deadline lastUpdate; + + /** + * Create a QUIC pacer for the given RTT estimator and congestion controller + * + * @param rttEstimator the RTT estimator + * @param congestionController the congestion controller + */ + public QuicPacer(QuicRttEstimator rttEstimator, + QuicCongestionController congestionController) { + this.rttEstimator = rttEstimator; + this.congestionController = congestionController; + this.appLimited = true; + } + + /** + * called to indicate that the flow is app-limited. + * Alters the behavior of the following updateQuota call. + */ + public void appLimited() { + appLimited = true; + } + + /** + * {@return true if pacer quota not hit yet, false otherwise} + */ + public boolean canSend() { + return quota >= congestionController.maxDatagramSize(); + } + + /** + * Update quota based on time since the last call to this method + * and whether appLimited() was called or not. + * + * @param now current time + */ + public void updateQuota(Deadline now) { + if (lastUpdate != null && !now.isAfter(lastUpdate)) { + // might happen when transmission tasks from different packet spaces + // race to update quota. Keep the most recent update only. + return; + } + long rttMicros = rttEstimator.state().smoothedRttMicros(); + long cwnd = congestionController.congestionWindow(); + if (rttMicros * TIMER_FREQ_HZ < TimeUnit.SECONDS.toMicros(2)) { + // RTT less than two timer periods; don't pace + quota = 2 * cwnd; + lastUpdate = now; + return; + } + long pacingRate = cwnd * (congestionController.isSlowStart() ? 2_000_000 : 1_250_000) / rttMicros; // bytes per second + long initialWindow = congestionController.initialWindow(); + long onePeriodWindow = pacingRate / TIMER_FREQ_HZ; + long maxQuota; + if (appLimited) { + maxQuota = Math.max(initialWindow, onePeriodWindow); + } else { + maxQuota = Math.max(2 * onePeriodWindow, 4 * congestionController.maxDatagramSize()); + } + if (lastUpdate == null) { + quota = Math.max(initialWindow, maxQuota); + } else { + long nanosSinceUpdate = Deadline.between(lastUpdate, now).toNanos(); + if (nanosSinceUpdate >= TimeUnit.MICROSECONDS.toNanos(rttMicros)) { + // don't bother computing the increment, it might overflow and will be capped to maxQuota anyway + quota = maxQuota; + if (Log.quicCC()) { + Log.logQuic("pacer cwnd: %s, rtt %s us, duration %s ns, quota: %s".formatted( + cwnd, rttMicros, nanosSinceUpdate, quota)); + } + } else { + long quotaIncrement = pacingRate * nanosSinceUpdate / 1_000_000_000; + quota += quotaIncrement; + quota = Math.min(quota, maxQuota); + if (Log.quicCC()) { + Log.logQuic("pacer cwnd: %s, rtt %s us, duration %s ns, increment %s, quota %s".formatted( + cwnd, rttMicros, nanosSinceUpdate, quotaIncrement, quota)); + } + } + } + lastUpdate = now; + appLimited = false; + } + + /** + * {@return the deadline when quota will increase to two packets} + */ + public Deadline twoPacketDeadline() { + long datagramSize = congestionController.maxDatagramSize(); + long quotaNeeded = datagramSize * 2 - quota; + if (quotaNeeded <= 0) { + assert canSend(); + return lastUpdate; + } + // Window increases at a rate of rtt / cwnd / N + long rttMicros = rttEstimator.state().smoothedRttMicros(); + long cwnd = congestionController.congestionWindow(); + return lastUpdate.plus(rttMicros + * (congestionController.isSlowStart() ? 500 : 800) /* 1000/N */ + * quotaNeeded / cwnd, ChronoUnit.NANOS); + } + + /** + * called to indicate that a packet was sent + * + * @param packetBytes packet size in bytes + */ + public void packetSent(int packetBytes) { + quota -= packetBytes; + } +} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicRenoCongestionController.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicRenoCongestionController.java index fde253740d1..2594c00055f 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicRenoCongestionController.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicRenoCongestionController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,15 +27,6 @@ package jdk.internal.net.http.quic; import jdk.internal.net.http.common.Deadline; import jdk.internal.net.http.common.Log; -import jdk.internal.net.http.common.TimeLine; -import jdk.internal.net.http.common.TimeSource; -import jdk.internal.net.http.common.Utils; -import jdk.internal.net.http.quic.frames.AckFrame; -import jdk.internal.net.http.quic.packets.QuicPacket; - -import java.util.Collection; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; /** * Implementation of QUIC congestion controller based on RFC 9002. @@ -46,35 +37,20 @@ import java.util.concurrent.locks.ReentrantLock; * @spec https://www.rfc-editor.org/info/rfc9002 * RFC 9002: QUIC Loss Detection and Congestion Control */ -class QuicRenoCongestionController implements QuicCongestionController { - // higher of 14720 and 2*maxDatagramSize; we use fixed maxDatagramSize - private static final int INITIAL_WINDOW = Math.max(14720, 2 * QuicConnectionImpl.DEFAULT_DATAGRAM_SIZE); - private static final int MAX_BYTES_IN_FLIGHT = Math.clamp( - Utils.getLongProperty("jdk.httpclient.quic.maxBytesInFlight", 1 << 24), - 1 << 14, 1 << 24); - private final TimeLine timeSource; - private final String dbgTag; - private final Lock lock = new ReentrantLock(); - private long congestionWindow = INITIAL_WINDOW; - private int maxDatagramSize = QuicConnectionImpl.DEFAULT_DATAGRAM_SIZE; - private int minimumWindow = 2 * maxDatagramSize; - private long bytesInFlight; - // maximum bytes in flight seen since the last congestion event - private long maxBytesInFlight; - private Deadline congestionRecoveryStartTime; - private long ssThresh = Long.MAX_VALUE; - - public QuicRenoCongestionController(String dbgTag) { - this.dbgTag = dbgTag; - this.timeSource = TimeSource.source(); +final class QuicRenoCongestionController extends QuicBaseCongestionController { + public QuicRenoCongestionController(String dbgTag, QuicRttEstimator rttEstimator) { + super(dbgTag, rttEstimator); } - private boolean inCongestionRecovery(Deadline sentTime) { - return (congestionRecoveryStartTime != null && - !sentTime.isAfter(congestionRecoveryStartTime)); + boolean congestionAvoidanceAcked(int packetBytes, Deadline sentTime) { + boolean isAppLimited = congestionWindow > maxBytesInFlight + 2L * maxDatagramSize; + if (!isAppLimited) { + congestionWindow += Math.max((long) maxDatagramSize * packetBytes / congestionWindow, 1L); + } + return isAppLimited; } - private void onCongestionEvent(Deadline sentTime) { + void onCongestionEvent(Deadline sentTime) { if (inCongestionRecovery(sentTime)) { return; } @@ -83,138 +59,9 @@ class QuicRenoCongestionController implements QuicCongestionController { congestionWindow = Math.max(minimumWindow, ssThresh); maxBytesInFlight = 0; if (Log.quicCC()) { - Log.logQuic(dbgTag+ " Congestion: ssThresh: " + ssThresh + + Log.logQuic(dbgTag + " Congestion: ssThresh: " + ssThresh + ", in flight: " + bytesInFlight + ", cwnd:" + congestionWindow); } } - - private static boolean inFlight(QuicPacket packet) { - // packet is in flight if it contains anything other than a single ACK frame - // specifically, a packet containing padding is considered to be in flight. - return packet.frames().size() != 1 || - !(packet.frames().get(0) instanceof AckFrame); - } - - @Override - public boolean canSendPacket() { - lock.lock(); - try { - if (bytesInFlight >= MAX_BYTES_IN_FLIGHT) { - return false; - } - var canSend = congestionWindow - bytesInFlight >= maxDatagramSize; - return canSend; - } finally { - lock.unlock(); - } - } - - @Override - public void updateMaxDatagramSize(int newSize) { - lock.lock(); - try { - if (minimumWindow != newSize * 2) { - minimumWindow = newSize * 2; - maxDatagramSize = newSize; - congestionWindow = Math.max(congestionWindow, minimumWindow); - } - } finally { - lock.unlock(); - } - } - - @Override - public void packetSent(int packetBytes) { - lock.lock(); - try { - bytesInFlight += packetBytes; - if (bytesInFlight > maxBytesInFlight) { - maxBytesInFlight = bytesInFlight; - } - } finally { - lock.unlock(); - } - } - - @Override - public void packetAcked(int packetBytes, Deadline sentTime) { - lock.lock(); - try { - bytesInFlight -= packetBytes; - // RFC 9002 says we should not increase cwnd when application limited. - // The concept itself is poorly defined. - // Here we limit cwnd growth based on the maximum bytes in flight - // observed since the last congestion event - if (inCongestionRecovery(sentTime)) { - if (Log.quicCC()) { - Log.logQuic(dbgTag+ " Acked, in recovery: bytes: " + packetBytes + - ", in flight: " + bytesInFlight); - } - return; - } - boolean isAppLimited; - if (congestionWindow < ssThresh) { - isAppLimited = congestionWindow >= 2 * maxBytesInFlight; - if (!isAppLimited) { - congestionWindow += packetBytes; - } - } else { - isAppLimited = congestionWindow > maxBytesInFlight + 2L * maxDatagramSize; - if (!isAppLimited) { - congestionWindow += Math.max((long) maxDatagramSize * packetBytes / congestionWindow, 1L); - } - } - if (Log.quicCC()) { - if (isAppLimited) { - Log.logQuic(dbgTag+ " Acked, not blocked: bytes: " + packetBytes + - ", in flight: " + bytesInFlight); - } else { - Log.logQuic(dbgTag + " Acked, increased: bytes: " + packetBytes + - ", in flight: " + bytesInFlight + - ", new cwnd:" + congestionWindow); - } - } - } finally { - lock.unlock(); - } - } - - @Override - public void packetLost(Collection lostPackets, Deadline sentTime, boolean persistent) { - lock.lock(); - try { - for (QuicPacket packet : lostPackets) { - if (inFlight(packet)) { - bytesInFlight -= packet.size(); - } - } - onCongestionEvent(sentTime); - if (persistent) { - congestionWindow = minimumWindow; - congestionRecoveryStartTime = null; - if (Log.quicCC()) { - Log.logQuic(dbgTag+ " Persistent congestion: ssThresh: " + ssThresh + - ", in flight: " + bytesInFlight + - ", cwnd:" + congestionWindow); - } - } - } finally { - lock.unlock(); - } - } - - @Override - public void packetDiscarded(Collection discardedPackets) { - lock.lock(); - try { - for (QuicPacket packet : discardedPackets) { - if (inFlight(packet)) { - bytesInFlight -= packet.size(); - } - } - } finally { - lock.unlock(); - } - } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicSelector.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicSelector.java index 9fa825459ff..02db895d27c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicSelector.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicSelector.java @@ -45,9 +45,9 @@ import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.TimeLine; import jdk.internal.net.http.common.TimeSource; import jdk.internal.net.http.common.Utils; +import jdk.internal.net.http.common.Utils.UseVTForSelector; import jdk.internal.net.http.quic.QuicEndpoint.QuicVirtualThreadedEndpoint; import jdk.internal.net.http.quic.QuicEndpoint.QuicSelectableEndpoint; -import jdk.internal.net.http.quic.QuicEndpoint.UseVTForSelector; import static jdk.internal.net.http.quic.QuicEndpoint.USE_VT_FOR_SELECTOR; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java index 9269b12bf64..ac885c1950e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicTimedEvent.java @@ -45,8 +45,7 @@ sealed interface QuicTimedEvent permits PacketSpaceManager.PacketTransmissionTask, QuicTimerQueue.Marker, QuicEndpoint.ClosedConnection, - IdleTimeoutManager.IdleTimeoutEvent, - IdleTimeoutManager.StreamDataBlockedEvent, + IdleTimeoutManager.TimedEvent, QuicConnectionImpl.MaxInitialTimer { /** diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/frames/AckFrame.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/frames/AckFrame.java index 7983d1be4f0..09d05f91066 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/frames/AckFrame.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/frames/AckFrame.java @@ -86,7 +86,7 @@ public final class AckFrame extends QuicFrame { } var ackRanges = new ArrayList(ackRangeCount + 1); AckRange first = AckRange.of(0, firstAckRange); - ackRanges.add(0, first); + ackRanges.addFirst(first); for (int i=1; i <= ackRangeCount; i++) { long gap = decodeVLField(buffer, "gap"); long len = decodeVLField(buffer, "range length"); @@ -139,10 +139,10 @@ public final class AckFrame extends QuicFrame { super(ACK); this.largestAcknowledged = requireVLRange(largestAcknowledged, "largestAcknowledged"); this.ackDelay = requireVLRange(ackDelay, "ackDelay"); - if (ackRanges.size() < 1) { + if (ackRanges.isEmpty()) { throw new IllegalArgumentException("insufficient ackRanges"); } - if (ackRanges.get(0).gap() != 0) { + if (ackRanges.getFirst().gap() != 0) { throw new IllegalArgumentException("first range must have zero gap"); } this.ackRanges = List.copyOf(ackRanges); @@ -178,7 +178,7 @@ public final class AckFrame extends QuicFrame { encodeVLField(buffer, largestAcknowledged, "largestAcknowledged"); encodeVLField(buffer, ackDelay, "ackDelay"); encodeVLField(buffer, ackRangeCount, "ackRangeCount"); - encodeVLField(buffer, ackRanges.get(0).range(), "firstAckRange"); + encodeVLField(buffer, ackRanges.getFirst().range(), "firstAckRange"); for (int i=1; i <= ackRangeCount; i++) { AckRange ar = ackRanges.get(i); encodeVLField(buffer, ar.gap(), "gap"); @@ -198,7 +198,7 @@ public final class AckFrame extends QuicFrame { + getVLFieldLengthFor(largestAcknowledged) + getVLFieldLengthFor(ackDelay) + getVLFieldLengthFor(ackRangeCount) - + getVLFieldLengthFor(ackRanges.get(0).range()) + + getVLFieldLengthFor(ackRanges.getFirst().range()) + ackRanges.stream().skip(1).mapToInt(AckRange::size).sum(); if (countsPresent) { size = size + getVLFieldLengthFor(ect0Count) @@ -236,7 +236,7 @@ public final class AckFrame extends QuicFrame { /** * {@return a new {@code AckFrame} identical to this one, but * with the given {@code ackDelay}}; - * @param ackDelay + * @param ackDelay the delay sending the Ack Frame */ public AckFrame withAckDelay(long ackDelay) { if (ackDelay == this.ackDelay) return this; @@ -361,9 +361,9 @@ public final class AckFrame extends QuicFrame { return null; } private final Iterator ackRangeIterator; - private volatile long largest; - private volatile long smallest; - private volatile long pn; // the current packet number + private long largest; + private long smallest; + private long pn; // the current packet number // The stream returns packet number in decreasing order // (largest packet number is returned first) @@ -377,7 +377,7 @@ public final class AckFrame extends QuicFrame { @Override public boolean tryAdvance(LongConsumer action) { // First call will see pn == 0 and smallest >= 2, - // which guarantees we will not enter the if below + // which guarantees we will not enter the `if` below // before pn has been initialized from the // first ackRange value if (pn >= smallest) { @@ -687,7 +687,7 @@ public final class AckFrame extends QuicFrame { return this; } else if (packetNumber == smallest - 1) { // Otherwise, if the packet number to be acknowledged is - // just below the smallest packet ackowledged by the current + // just below the smallest packet acknowledged by the current // range, there are again two cases, depending on // whether the next ackRange has a gap that can be reduced, // or not @@ -855,7 +855,7 @@ public final class AckFrame extends QuicFrame { private AckFrameBuilder acknowledgeLargerPacket(long largerThanLargest) { var packetNumber = largerThanLargest; // the new packet is larger than the largest acknowledged - var firstAckRange = ackRanges.get(0); + var firstAckRange = ackRanges.getFirst(); if (largestAcknowledged == packetNumber -1) { // if packetNumber is largestAcknowledged + 1, we can simply // extend the first ack range by 1 @@ -864,7 +864,7 @@ public final class AckFrame extends QuicFrame { } else { // otherwise - we have a gap - we need to acknowledge the new packetNumber, // and then add the gap that separate it from the previous largestAcknowledged... - ackRanges.add(0, AckRange.INITIAL); // acknowledge packetNumber only + ackRanges.addFirst(AckRange.INITIAL); // acknowledge packetNumber only long gap = packetNumber - largestAcknowledged -2; var secondAckRange = AckRange.of(gap, firstAckRange.range); ackRanges.set(1, secondAckRange); // add the gap diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java index 890c1a63a35..db519dc7557 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/packets/QuicPacketEncoder.java @@ -577,7 +577,6 @@ public class QuicPacketEncoder { final byte[] encodedPacketNumber; final List frames; final int payloadSize; - private int tagSize; OutgoingHandshakePacket(QuicConnectionId sourceId, QuicConnectionId destinationId, @@ -590,7 +589,6 @@ public class QuicPacketEncoder { this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); this.payloadSize = frames.stream().mapToInt(QuicFrame::size).reduce(0, Math::addExact); - this.tagSize = tagSize; this.length = computeLength(payloadSize, encodedPacketNumber.length, tagSize); this.size = computeSize(length); } @@ -676,7 +674,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; OutgoingZeroRttPacket(QuicConnectionId sourceId, @@ -689,7 +686,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream().mapToInt(QuicFrame::size) .reduce(0, Math::addExact); this.length = computeLength(payloadSize, encodedPacketNumber.length, tagSize); @@ -778,7 +774,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; OutgoingOneRttPacket(QuicConnectionId destinationId, @@ -789,7 +784,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream().mapToInt(QuicFrame::size) .reduce(0, Math::addExact); this.size = computeSize(payloadSize, encodedPacketNumber.length, tagSize); @@ -853,7 +847,6 @@ public class QuicPacketEncoder { final int size; final byte[] encodedPacketNumber; final List frames; - private int tagSize; final int payloadSize; private record InitialPacketVariableComponents(int length, byte[] token, QuicConnectionId sourceId, @@ -873,7 +866,6 @@ public class QuicPacketEncoder { this.packetNumber = packetNumber; this.encodedPacketNumber = encodedPacketNumber; this.frames = List.copyOf(frames); - this.tagSize = tagSize; this.payloadSize = this.frames.stream() .mapToInt(QuicFrame::size) .reduce(0, Math::addExact); diff --git a/src/java.sql/share/classes/java/sql/Array.java b/src/java.sql/share/classes/java/sql/Array.java index 1c42d3e5b79..8fe84f4f930 100644 --- a/src/java.sql/share/classes/java/sql/Array.java +++ b/src/java.sql/share/classes/java/sql/Array.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,13 +61,19 @@ package java.sql; * If the connection's type map or a type map supplied to a method has no entry * for the base type, the elements are mapped according to the standard mapping. *

    + * To release resources used by the {@code Array} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code Array} object has been closed, will result in a {@link SQLException} + * being thrown. + *

    * All methods on the {@code Array} interface must be fully implemented if the * JDBC driver supports the data type. * * @since 1.2 */ -public interface Array { +public interface Array extends AutoCloseable { /** * Retrieves the SQL type name of the elements in @@ -345,21 +351,35 @@ public interface Array { java.util.Map> map) throws SQLException; /** - * This method frees the {@code Array} object and releases the resources that - * it holds. The object is invalid once the {@code free} - * method is called. + * Closes and releases the resources held by this {@code Array} object. *

    - * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in a {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. + * If the {@code Array} object is already closed, then invoking this method + * has no effect. * * @throws SQLException if an error occurs releasing * the Array's resources * @throws SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since 1.6 + * @see #close() */ void free() throws SQLException; + /** + * Closes and releases the resources held by this {@code Array} object. + *

    + * If the {@code Array} object is already closed, then invoking this method + * has no effect. + * + * @throws SQLException if an error occurs releasing + * the Array's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @implSpec The default implementation calls the {@link #free()} method. + * @see #free() + * @since 26 + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Blob.java b/src/java.sql/share/classes/java/sql/Blob.java index 5bf9cfcb7ad..4f5619616eb 100644 --- a/src/java.sql/share/classes/java/sql/Blob.java +++ b/src/java.sql/share/classes/java/sql/Blob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ import java.io.InputStream; * the Java programming language of an SQL * {@code BLOB} value. An SQL {@code BLOB} is a built-in type * that stores a Binary Large Object as a column value in a row of - * a database table. By default drivers implement {@code Blob} using + * a database table. By default, drivers implement {@code Blob} using * an SQL {@code locator(BLOB)}, which means that a * {@code Blob} object contains a logical pointer to the * SQL {@code BLOB} data rather than the data itself. @@ -50,13 +50,19 @@ import java.io.InputStream; * {@code BLOB} value. In addition, this interface has methods for updating * a {@code BLOB} value. *

    + * To release resources used by the {@code Blob} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code Blob} object has been closed, will result in a {@link SQLException} + * being thrown. + *

    * All methods on the {@code Blob} interface must be fully implemented if the * JDBC driver supports the data type. * * @since 1.2 */ -public interface Blob { +public interface Blob extends AutoCloseable { /** * Returns the number of bytes in the {@code BLOB} value @@ -266,20 +272,17 @@ public interface Blob { void truncate(long len) throws SQLException; /** - * This method frees the {@code Blob} object and releases the resources that - * it holds. The object is invalid once the {@code free} - * method is called. + * Closes and releases the resources held by this {@code Blob} object. *

    - * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in an {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. + * If the {@code Blob} object is already closed, then invoking this method + * has no effect. * * @throws SQLException if an error occurs releasing * the Blob's resources * @throws SQLFeatureNotSupportedException if the JDBC driver * does not support this method * @since 1.6 + * @see #close() */ void free() throws SQLException; @@ -303,4 +306,23 @@ public interface Blob { * @since 1.6 */ InputStream getBinaryStream(long pos, long length) throws SQLException; + + /** + * Closes and releases the resources held by this {@code Blob} object. + *

    + * If the {@code Blob} object is already closed, then invoking this method + * has no effect. + * + * @implSpec The default implementation calls the {@link #free()} method. + * + * @throws SQLException if an error occurs releasing + * the Blob's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @since 26 + * @see #free() + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Clob.java b/src/java.sql/share/classes/java/sql/Clob.java index 15e6897f711..141f7de81af 100644 --- a/src/java.sql/share/classes/java/sql/Clob.java +++ b/src/java.sql/share/classes/java/sql/Clob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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,7 +33,7 @@ import java.io.Reader; * An SQL {@code CLOB} is a built-in type * that stores a Character Large Object as a column value in a row of * a database table. - * By default drivers implement a {@code Clob} object using an SQL + * By default, drivers implement a {@code Clob} object using an SQL * {@code locator(CLOB)}, which means that a {@code Clob} object * contains a logical pointer to the SQL {@code CLOB} data rather than * the data itself. A {@code Clob} object is valid for the duration @@ -49,13 +49,19 @@ import java.io.Reader; * access an SQL {@code CLOB} value. In addition, this interface * has methods for updating a {@code CLOB} value. *

    + * To release resources used by the {@code Clob} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code Clob} object has been closed, will result in a {@link SQLException} + * being thrown. + *

    * All methods on the {@code Clob} interface must be * fully implemented if the JDBC driver supports the data type. * * @since 1.2 */ -public interface Clob { +public interface Clob extends AutoCloseable { /** * Retrieves the number of characters @@ -310,14 +316,10 @@ public interface Clob { void truncate(long len) throws SQLException; /** - * This method releases the resources that the {@code Clob} object - * holds. The object is invalid once the {@code free} method - * is called. + * Closes and releases the resources held by this {@code Clob} object. *

    - * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in a {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. + * If the {@code Clob} object is already closed, then invoking this method + * has no effect. * * @throws SQLException if an error occurs releasing * the Clob's resources @@ -325,6 +327,7 @@ public interface Clob { * @throws SQLFeatureNotSupportedException if the JDBC driver * does not support this method * @since 1.6 + * @see #close() */ void free() throws SQLException; @@ -350,4 +353,21 @@ public interface Clob { */ Reader getCharacterStream(long pos, long length) throws SQLException; + /** + * Closes and releases the resources held by this {@code Clob} object. + *

    + * If the {@code Clob} object is already closed, then invoking this method + * has no effect. + * + * @throws SQLException if an error occurs releasing + * the Clob's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @implSpec The default implementation calls the {@link #free()} method. + * @see #free() + * @since 26 + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Connection.java b/src/java.sql/share/classes/java/sql/Connection.java index 19f283f5762..946459adf7b 100644 --- a/src/java.sql/share/classes/java/sql/Connection.java +++ b/src/java.sql/share/classes/java/sql/Connection.java @@ -43,8 +43,8 @@ import java.util.Map; * should use the appropriate {@code Connection} method such as * {@code setAutoCommit} or {@code setTransactionIsolation}. * Applications should not invoke SQL commands directly to change the connection's - * configuration when there is a JDBC method available. By default a {@code Connection} object is in - * auto-commit mode, which means that it automatically commits changes + * configuration when there is a JDBC method available. By default, a {@code Connection} + * object is in auto-commit mode, which means that it automatically commits changes * after executing each statement. If auto-commit mode has been * disabled, the method {@code commit} must be called explicitly in * order to commit changes; otherwise, database changes will not be saved. @@ -77,7 +77,7 @@ import java.util.Map; * con.setTypeMap(map); *

    * - * @see DriverManager#getConnection + * @see DriverManager#getConnection(String) * @see Statement * @see ResultSet * @see DatabaseMetaData @@ -1505,7 +1505,7 @@ public interface Connection extends Wrapper, AutoCloseable { * * @throws SQLException if an error occurs * @since 9 - * @see endRequest + * @see #endRequest() * @see javax.sql.PooledConnection */ default void beginRequest() throws SQLException { @@ -1548,7 +1548,7 @@ public interface Connection extends Wrapper, AutoCloseable { * * @throws SQLException if an error occurs * @since 9 - * @see beginRequest + * @see #beginRequest() * @see javax.sql.PooledConnection */ default void endRequest() throws SQLException { @@ -1676,5 +1676,311 @@ public interface Connection extends Wrapper, AutoCloseable { default void setShardingKey(ShardingKey shardingKey) throws SQLException { throw new SQLFeatureNotSupportedException("setShardingKey not implemented"); } + // JDBC 4.5 + /** + * Returns a {@code String} enclosed in single quotes. Any occurrence of a + * single quote within the string will be replaced by two single quotes. + * + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    ValueResult
    Hello 'Hello'
    G'Day 'G''Day'
    'G''Day''''G''''Day'''
    I'''M 'I''''''M'
    + *
    + * @implSpec + * The default implementation creates the literal as: + * {@code "'" + val.replace("'", "''") + "'"}. + * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + * @param val a character string + * @return A string enclosed by single quotes with every single quote + * converted to two single quotes + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * + * @since 26 + */ + default String enquoteLiteral(String val) throws SQLException { + return SQLUtils.enquoteLiteral(val); + } + + /** + * Returns a {@link #isSimpleIdentifier(String) simple SQL identifier} or a + * delimited identifier. A delimited identifier represents the name of a + * database object such as a table, column, or view that is enclosed by a + * delimiter, which is typically a double quote as defined by the SQL standard. + *

    + * If {@code identifier} is a simple SQL identifier: + *

      + *
    • If {@code alwaysDelimit} is {@code false}, return the original value
    • + *
    • if {@code alwaysDelimit} is {@code true}, enquote the original value + * and return as a delimited identifier
    • + *
    + * + * If {@code identifier} is not a simple SQL identifier, the delimited + * {@code identifier} to be returned must be enclosed by the delimiter + * returned from {@link DatabaseMetaData#getIdentifierQuoteString}. If + * the datasource does not support delimited identifiers, a + * {@code SQLFeatureNotSupportedException} is thrown. + *

    + * A {@code SQLException} will be thrown if {@code identifier} contains any + * invalid characters within a delimited identifier or the identifier length + * is invalid for the datasource. + * + * @implSpec + * The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + *

      + *
    • The string is not enclosed in double quotes
    • + *
    • The first character is an alphabetic character from a ({@code '\u005C0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters([0-9A-Za-z]) + * or the character "_"
    • + *
    + * + * The default implementation will throw a {@code SQLException} if: + *
      + *
    • {@link DatabaseMetaData#getIdentifierQuoteString} does not return a + * double quote
    • + *
    • {@code identifier} contains a {@code null} character or double quote
    • + *
    • The length of {@code identifier} is less than 1 or greater than 128 characters + *
    + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    identifieralwaysDelimitResult
    HellofalseHello
    Hellotrue"Hello"
    G'Dayfalse"G'Day"
    "Bruce Wayne"false"Bruce Wayne"
    "Bruce Wayne"true"Bruce Wayne"
    "select"false"select"
    "select"true"select"
    GoodDay$false"GoodDay$"
    Hello"WorldfalseSQLException
    "Hello"World"falseSQLException
    + *
    + * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + * @param identifier a SQL identifier + * @param alwaysDelimit indicates if a simple SQL identifier should be + * returned as a delimited identifier + * @return A simple SQL identifier or a delimited identifier + * @throws SQLException if identifier is not a valid identifier + * @throws SQLFeatureNotSupportedException if the datasource does not support + * delimited identifiers + * @throws NullPointerException if identifier is {@code null} + * + * @since 26 + */ + default String enquoteIdentifier(String identifier, boolean alwaysDelimit) throws SQLException { + String delimiter = this.getMetaData().getIdentifierQuoteString(); + return SQLUtils.enquoteIdentifier(delimiter, identifier, alwaysDelimit); + } + + /** + * Returns whether {@code identifier} is a simple SQL identifier. + * A simple SQL identifier is referred to as regular (or ordinary) identifier + * within the SQL standard. A regular identifier represents the name of a database + * object such as a table, column, or view. + *

    + * The rules for a regular Identifier are: + *

      + *
    • The first character is an alphabetic character from a ({@code '\u005Cu0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters([0-9A-Za-z]) + * or the character "_"
    • + *
    • It cannot be a SQL reserved word
    • + *
    + *

    + * A datasource may have additional rules for a regular identifier such as: + *

      + *
    • Supports additional characters within the name based on + * the locale being used
    • + *
    • Supports a different maximum length for the identifier
    • + *
    + * + * @implSpec The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + *
      + *
    • The identifier is not enclosed in double quotes
    • + *
    • The first character is an alphabetic character from a through z, or + * from A through Z
    • + *
    • The identifier only contains alphanumeric characters([0-9A-Za-z]) or + * the character "_"
    • + *
    • The identifier is not a SQL reserved word
    • + *
    • The identifier is between 1 and 128 characters in length inclusive
    • + *
    + * + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    identifierSimple Identifier
    Hellotrue
    G'Dayfalse
    "Bruce Wayne"false
    GoodDay$false
    Hello"Worldfalse
    "Hello"World"false
    "select"false
    "from"false
    + *
    + * @implNote JDBC driver implementations may need to provide their own + * implementation of this method in order to meet the requirements of the + * underlying datasource. + * @param identifier a SQL identifier + * @return true if a simple SQL identifier, false otherwise + * @throws NullPointerException if identifier is {@code null} + * @throws SQLException if a database access error occurs + * + * @since 26 + */ + default boolean isSimpleIdentifier(String identifier) throws SQLException { + return SQLUtils.isSimpleIdentifier(identifier); + } + + /** + * Returns a {@code String} representing a National Character Set Literal + * enclosed in single quotes and prefixed with a upper case letter N. + * Any occurrence of a single quote within the string will be replaced + * by two single quotes. + * + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    ValueResult
    Hello N'Hello'
    G'Day N'G''Day'
    'G''Day'N'''G''''Day'''
    I'''M N'I''''''M'
    N'Hello' N'N''Hello'''
    + *
    + * @implSpec + * The default implementation creates the literal as: + * {@code "N'" + val.replace("'", "''") + "'"}. + * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. An implementation of enquoteNCharLiteral may accept a different + * set of characters than that accepted by the same drivers implementation of + * enquoteLiteral. + * @param val a character string + * @return the result of replacing every single quote character in the + * argument by two single quote characters where this entire result is + * then prefixed with 'N'. + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * + * @since 26 + */ + default String enquoteNCharLiteral(String val) throws SQLException { + return SQLUtils.enquoteNCharLiteral(val); + } } diff --git a/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java b/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java index c5f5fc30ee9..426a49b7ae0 100644 --- a/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java +++ b/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,13 @@ package java.sql; +import java.util.Properties; + /** *

    Driver properties for making a connection. The - * {@code DriverPropertyInfo} class is of interest only to advanced programmers - * who need to interact with a Driver via the method - * {@code getDriverProperties} to discover - * and supply properties for connections. + * {@code DriverPropertyInfo} class is of interest only to advanced programmers. + * The method {@link Driver#getPropertyInfo(String, Properties)} may be used + * to discover Driver properties. * * @since 1.1 */ diff --git a/src/java.sql/share/classes/java/sql/JDBCType.java b/src/java.sql/share/classes/java/sql/JDBCType.java index 9c9d314b7f1..9da51c27925 100644 --- a/src/java.sql/share/classes/java/sql/JDBCType.java +++ b/src/java.sql/share/classes/java/sql/JDBCType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, 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 @@ -200,7 +200,21 @@ public enum JDBCType implements SQLType { /** * Identifies the generic SQL type {@code TIMESTAMP_WITH_TIMEZONE}. */ - TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE); + TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE), + + /* JDBC 4.5 Types */ + + /** + * Identifies the generic SQL type {@code DECFLOAT}. + * @since 26 + */ + DECFLOAT(Types.DECFLOAT), + + /** + * Identifies the generic SQL type {@code JSON}. + * @since 26 + */ + JSON(Types.JSON); /** * The Integer value for the JDBCType. It maps to a value in diff --git a/src/java.sql/share/classes/java/sql/NClob.java b/src/java.sql/share/classes/java/sql/NClob.java index 587f6e1f843..0639f894146 100644 --- a/src/java.sql/share/classes/java/sql/NClob.java +++ b/src/java.sql/share/classes/java/sql/NClob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,8 @@ package java.sql; * An SQL {@code NCLOB} is a built-in type * that stores a Character Large Object using the National Character Set * as a column value in a row of a database table. - *

    The {@code NClob} interface extends the {@code Clob} interface + *

    + * The {@code NClob} interface extends the {@code Clob} interface * which provides methods for getting the * length of an SQL {@code NCLOB} value, * for materializing a {@code NCLOB} value on the client, and for @@ -44,6 +45,12 @@ package java.sql; * access an SQL {@code NCLOB} value. In addition, this interface * has methods for updating a {@code NCLOB} value. *

    + * To release resources used by the {@code NClob} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code NClob} object has been closed, will result in a {@link SQLException} + * being thrown. + *

    * All methods on the {@code NClob} interface must be fully implemented if the * JDBC driver supports the data type. * diff --git a/src/java.sql/share/classes/java/sql/SQLPermission.java b/src/java.sql/share/classes/java/sql/SQLPermission.java index 84e41c51a33..f9a0c7e2ed6 100644 --- a/src/java.sql/share/classes/java/sql/SQLPermission.java +++ b/src/java.sql/share/classes/java/sql/SQLPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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 @@ -29,30 +29,14 @@ package java.sql; import java.security.*; /** - * A {@code SQLPermission} object contains - * a name (also referred to as a "target name") but no actions - * list; there is either a named permission or there is not. - * The target name is the name of the permission. The - * naming convention follows the hierarchical property naming convention. - * In addition, an asterisk - * may appear at the end of the name, following a ".", or by itself, to - * signify a wildcard match. For example: {@code loadLibrary.*} - * and {@code *} signify a wildcard match, - * while {@code *loadLibrary} and {@code a*b} do not. - * - * @apiNote - * This permission cannot be used for controlling access to resources - * as the Security Manager is no longer supported. + * This class was only useful in conjunction with the {@link java.lang.SecurityManager}, + * which is no longer supported. There is no replacement for this class. * * @since 1.3 - * @see java.security.BasicPermission - * @see java.security.Permission - * @see java.security.Permissions - * @see java.security.PermissionCollection - * @see java.lang.SecurityManager * + * @deprecated There is no replacement for this class. */ - +@Deprecated(since="26", forRemoval=true) public final class SQLPermission extends BasicPermission { /** diff --git a/src/java.sql/share/classes/java/sql/SQLUtils.java b/src/java.sql/share/classes/java/sql/SQLUtils.java new file mode 100644 index 00000000000..49757d7e8ad --- /dev/null +++ b/src/java.sql/share/classes/java/sql/SQLUtils.java @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.sql; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * Utility class used by the Connection & Statement interfaces for their + * shared default methods. + */ +class SQLUtils { + // Pattern used to verify if an identifier is a Simple SQL identifier + private static final Pattern SIMPLE_IDENTIFIER_PATTERN + = Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*"); + // Pattern to check if an identifier contains a null character or a double quote + private static final Pattern INVALID_IDENTIFIER_CHARACTERS_PATTERN + = Pattern.compile("[^\u0000\"]+"); + // SQL 2023 reserved words + private static final String[] SQL2023_RESERVED_WORDS = { + "ABS", "ABSENT", "ACOS", "ALL", "ALLOCATE", "ALTER", "AND", "ANY", + "ANY_VALUE", "ARE", "ARRAY", "ARRAY_AGG", "ARRAY_MAX_CARDINALITY", + "AS", "ASENSITIVE", "ASIN", "ASYMMETRIC", "AT", "ATAN", + "ATOMIC", "AUTHORIZATION", "AVG", + "BEGIN", "BEGIN_FRAME", "BEGIN_PARTITION", "BETWEEN", "BIGINT", + "BINARY", "BLOB", "BOOLEAN", "BOTH", "BTRIM", "BY", + "CALL", "CALLED", "CARDINALITY", "CASCADED", "CASE", "CAST", "CEIL", + "CEILING", "CHAR", "CHAR_LENGTH", + "CHARACTER", "CHARACTER_LENGTH", "CHECK", "CLASSIFIER", "CLOB", + "CLOSE", "COALESCE", "COLLATE", "COLLECT", "COLUMN", "COMMIT", "CONDITION", + "CONNECT", "CONSTRAINT", "CONTAINS", "CONVERT", "COPY", "CORR", "CORRESPONDING", + "COS", "COSH", "COUNT", "COVAR_POP", "COVAR_SAMP", "CREATE", "CROSS", "CUBE", + "CUME_DIST", "CURRENT", + "CURRENT_CATALOG", "CURRENT_DATE", "CURRENT_DEFAULT_TRANSFORM_GROUP", "CURRENT_PATH", + "CURRENT_ROLE", "CURRENT_SCHEMA", "CURRENT_TIME", "CURRENT_TIMESTAMP", + "CURRENT_TRANSFORM_GROUP_FOR_TYPE", "CURRENT_USER", "CURSOR", "CYCLE", + "DATE", "DAY", "DEALLOCATE", "DEC", "DECFLOAT", "DECIMAL", "DECLARE", "DEFAULT", + "DEFINE", "DELETE", "DENSE_RANK", "DEREF", "DESCRIBE", "DETERMINISTIC", + "DISCONNECT", "DISTINCT", "DOUBLE", "DROP", "DYNAMIC", + "EACH", "ELEMENT", "ELSE", "EMPTY", "END", "END_FRAME", "END_PARTITION", + "END-EXEC", "EQUALS", "ESCAPE", "EVERY", "EXCEPT", "EXEC", "EXECUTE", + "EXISTS", "EXP", "EXTERNAL", "EXTRACT", + "FALSE", "FETCH", "FILTER", "FIRST_VALUE", "FLOAT", "FLOOR", "FOR", "FOREIGN", "FRAME_ROW", + "FREE", "FROM", "FULL", "FUNCTION", "FUSION", + "GET", "GLOBAL", "GRANT", "GREATEST", "GROUP", "GROUPING", "GROUPS", + "HAVING", "HOLD", "HOUR", + "IDENTITY", "IN", "INDICATOR", "INITIAL", "INNER", "INOUT", "INSENSITIVE", + "INSERT", "INT", "INTEGER", + "INTERSECT", "INTERSECTION", "INTERVAL", "INTO", "IS", + "JOIN", "JSON", "JSON_ARRAY", "JSON_ARRAYAGG", "JSON_EXISTS", + "JSON_OBJECT", "JSON_OBJECTAGG", "JSON_QUERY", "JSON_SCALAR", + "JSON_SERIALIZE", "JSON_TABLE", "JSON_TABLE_PRIMITIVE", "JSON_VALUE", + "LAG", "LANGUAGE", "LARGE", " LAST_VALUE", "LATERAL", "LEAD", + "LEADING", "LEAST", "LEFT", "LIKE", "LIKE_REGEX", "LISTAGG", + "LN", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOG", "LOG10", + "LOWER", "LPAD", "LTRIM", + "MATCH", "MATCH_NUMBER", "MATCH_RECOGNIZE", "MATCHES", "MAX", + "MEMBER", "MERGE", "METHOD", "MIN", "MINUTE", "MOD", "MODIFIES", + "MODULE", "MONTH", "MULTISET", + "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NEW", "NO", "NONE", + "NORMALIZE", "NOT", "NTH_VALUE", "NTILE", "NULL", "NULLIF", "NUMERIC", + "OCCURRENCES_REGEX", "OCTET_LENGTH", "OF", "OFFSET", "OLD", "OMIT", + "ON", "ONE", "ONLY", "OPEN", "OR", "ORDER", "OUT", "OUTER", "OUTPUT", + "OVER", "OVERLAPS", "OVERLAY", + "PARAMETER", "PARTITION", "PATTERN", "PER", "PERCENT", "PERCENT_RANK", + "PERCENTILE_CONT", "PERCENTILE_DISC", "PERIOD", "PORTION", "POSITION", + "POSITION_REGEX", "POWER", "PRECEDES", + "PRECISION", "PREPARE", "PRIMARY", "PROCEDURE", "PTF", + "RANGE", "RANK", "READS", "REAL", "RECURSIVE", "REF", "REFERENCES", + "REFERENCING", "REGR_AVGX", "REGR_AVGY", "REGR_COUNT", "REGR_INTERCEPT", + "REGR_R2", "REGR_SLOPE", "REGR_SXX", "REGR_SXY", "REGR_SYY", + "RELEASE", "RESULT", "RETURN", "RETURNS", "REVOKE", "RIGHT", + "ROLLBACK", "ROLLUP", "ROW", "ROW_NUMBER", "ROWS", "RPAD", "RTRIM", + "RUNNING", + "SAVEPOINT", "SCOPE", "SCROLL", "SEARCH", "SECOND", "SEEK", + "SELECT", "SENSITIVE", "SESSION_USER", "SET", "SHOW", "SIMILAR", + "SIN", "SINH", "SKIP", "SMALLINT", + "SOME", "SPECIFIC", "SPECIFICTYPE", "SQL", "SQLEXCEPTION", "SQLSTATE", + "SQLWARNING", "SQRT", "START", "STATIC", "STDDEV_POP", "STDDEV_SAMP", + "SUBMULTISET", "SUBSET", "SUBSTRING", "SUBSTRING_REGEX", "SUCCEEDS", + "SUM", "SYMMETRIC", "SYSTEM", "SYSTEM_TIME", "SYSTEM_USER", + "TABLE", "TABLESAMPLE", "TAN", "TANH", "THEN", "TIME", "TIMESTAMP", + "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", "TRAILING", "TRANSLATE", + "TRANSLATE_REGEX", "TRANSLATION", "TREAT", "TRIGGER", "TRIM", + "TRIM_ARRAY", "TRUE", "TRUNCATE", + "UESCAPE", "UNION", "UNIQUE", "UNKNOWN", "UNNEST", "UPDATE", "UPPER", + "USER", "USING", + "VALUE", "VALUES", "VALUE_OF", "VAR_POP", "VAR_SAMP", "VARBINARY", + "VARCHAR", "VARYING", "VERSIONING", + "WHEN", "WHENEVER", "WHERE", "WHILE", "WIDTH_BUCKET", "WINDOW", + "WITH", "WITHIN", "WITHOUT", + "YEAR" + }; + private static final Set SQL_RESERVED_WORDS = + new HashSet<>(Arrays.asList(SQL2023_RESERVED_WORDS)); + + /** + * Returns a {@code String} enclosed in single quotes. Any occurrence of a + * single quote within the string will be replaced by two single quotes. + * + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    ValueResult
    Hello 'Hello'
    G'Day 'G''Day'
    'G''Day''''G''''Day'''
    I'''M 'I''''''M'
    + *
    + * + * @param val a character string + * @return A string enclosed by single quotes with every single quote + * converted to two single quotes + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * @implNote JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + */ + static String enquoteLiteral(String val) throws SQLException { + return "'" + val.replace("'", "''") + "'"; + } + + /** + * Returns a {@link #isSimpleIdentifier(String) simple SQL identifier} or a + * delimited identifier. A delimited identifier represents the name of a + * database object such as a table, column, or view that is enclosed by a + * delimiter, which is typically a double quote as defined by the SQL standard. + *

    + * If {@code identifier} is a simple SQL identifier: + *

      + *
    • If {@code alwaysDelimit} is {@code false}, return the original value
    • + *
    • if {@code alwaysDelimit} is {@code true}, enquote the original value + * and return as a delimited identifier
    • + *
    + * + * If {@code identifier} is not a simple SQL identifier, the delimited + * {@code identifier} to be returned must be enclosed by the delimiter + * returned from {@link DatabaseMetaData#getIdentifierQuoteString}. If + * the datasource does not support delimited identifiers, a + * {@code SQLFeatureNotSupportedException} is thrown. + *

    + * A {@code SQLException} will be thrown if {@code identifier} contains any + * invalid characters within a delimited identifier or the identifier length + * is invalid for the datasource. + * + * @implSpec + * The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + *

      + *
    • The string is not enclosed in double quotes
    • + *
    • The first character is an alphabetic character from a ({@code '\u005C0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters or the character "_"
    • + *
    + * + * The default implementation will throw a {@code SQLException} if: + *
      + *
    • {@link DatabaseMetaData#getIdentifierQuoteString} does not return a + * double quote
    • + *
    • {@code identifier} contains a {@code null} character or double quote
    • + *
    • The length of {@code identifier} is less than 1 or greater than 128 characters + *
    + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    identifieralwaysDelimitResult
    HellofalseHello
    Hellotrue"Hello"
    G'Dayfalse"G'Day"
    "Bruce Wayne"false"Bruce Wayne"
    "Bruce Wayne"true"Bruce Wayne"
    "select"false"select"
    "select"true"select"
    GoodDay$false"GoodDay$"
    Hello"WorldfalseSQLException
    "Hello"World"falseSQLException
    + *
    + * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + * @param identifier a SQL identifier + * @param alwaysDelimit indicates if a simple SQL identifier should be + * returned as a delimited identifier + * @return A simple SQL identifier or a delimited identifier + * @throws SQLException if identifier is not a valid identifier + * @throws SQLFeatureNotSupportedException if the datasource does not support + * delimited identifiers + * @throws NullPointerException if identifier is {@code null} + */ + static String enquoteIdentifier(String delimiter, String identifier, boolean alwaysDelimit) throws SQLException { + int len = identifier.length(); + if (len < 1 || len > 128) { + throw new SQLException("Invalid identifier length"); + } + if (!delimiter.equals("\"")) { + throw new SQLException("Unsupported delimiter"); + } + if (isSimpleIdentifier(identifier)) { + return alwaysDelimit ? "\"" + identifier + "\"" : identifier; + } + if (identifier.matches("^\".+\"$")) { + identifier = identifier.substring(1, len - 1); + } + // Enclose the identifier in double quotes. If the identifier + // contains a null character or a double quote, throw a SQLException + if (INVALID_IDENTIFIER_CHARACTERS_PATTERN.matcher(identifier).matches()) { + return "\"" + identifier + "\""; + } else { + throw new SQLException("Invalid name"); + } + } + + /** + * Returns whether {@code identifier} is a simple SQL identifier. + * A simple SQL identifier is referred to as regular (or ordinary) identifier + * within the SQL standard. A regular identifier represents the name of a database + * object such as a table, column, or view. + *

    + * The rules for a regular Identifier are: + *

      + *
    • The first character is an alphabetic character from a ({@code '\u005Cu0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters or the character "_"
    • + *
    • It cannot be a SQL reserved word
    • + *
    + *

    + * A datasource may have additional rules for a regular identifier such as: + *

      + *
    • Supports additional characters within the name based on + * the locale being used
    • + *
    • Supports a different maximum length for the identifier
    • + *
    + * + * @implSpec The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + *
      + *
    • The identifier is not enclosed in double quotes
    • + *
    • The first character is an alphabetic character from a through z, or + * from A through Z
    • + *
    • The identifier only contains alphanumeric characters or the character + * "_"
    • + *
    • The identifier is not a SQL reserved word
    • + *
    • The identifier is between 1 and 128 characters in length inclusive
    • + *
    + * + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    identifierSimple Identifier
    Hellotrue
    G'Dayfalse
    "Bruce Wayne"false
    GoodDay$false
    Hello"Worldfalse
    "Hello"World"false
    "select"false
    "from"false
    + *
    + * @implNote JDBC driver implementations may need to provide their own + * implementation of this method in order to meet the requirements of the + * underlying datasource. + * @param identifier a SQL identifier + * @return true if a simple SQL identifier, false otherwise + * @throws NullPointerException if identifier is {@code null} + * @throws SQLException if a database access error occurs + */ + static boolean isSimpleIdentifier(String identifier) throws SQLException { + int len = identifier.length(); + return !SQL_RESERVED_WORDS.contains(identifier.toUpperCase()) && + len >= 1 && len <= 128 + && SIMPLE_IDENTIFIER_PATTERN.matcher(identifier).matches(); + } + + /** + * Returns a {@code String} representing a National Character Set Literal + * enclosed in single quotes and prefixed with an upper case letter N. + * Any occurrence of a single quote within the string will be replaced + * by two single quotes. + * + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Examples of the conversion:
    ValueResult
    Hello N'Hello'
    G'Day N'G''Day'
    'G''Day'N'''G''''Day'''
    I'''M N'I''''''M'
    N'Hello' N'N''Hello'''
    + *
    + * + * @param val a character string + * @return the result of replacing every single quote character in the + * argument by two single quote characters where this entire result is + * then prefixed with 'N'. + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * @implNote JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. An implementation of enquoteNCharLiteral may accept a different + * set of characters than that accepted by the same drivers implementation of + * enquoteLiteral. + */ + static String enquoteNCharLiteral(String val) throws SQLException { + return "N'" + val.replace("'", "''") + "'"; + } +} diff --git a/src/java.sql/share/classes/java/sql/SQLXML.java b/src/java.sql/share/classes/java/sql/SQLXML.java index 3edae8a9508..70d481822e2 100644 --- a/src/java.sql/share/classes/java/sql/SQLXML.java +++ b/src/java.sql/share/classes/java/sql/SQLXML.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -170,14 +170,19 @@ import javax.xml.transform.Source; * The conceptual states of writable and not writable determine if one * of the writing APIs will set a value or throw an exception. *

    - * The state moves from readable to not readable once free() or any of the + * The state moves from readable to not readable once close(), free() or any of the * reading APIs are called: getBinaryStream(), getCharacterStream(), getSource(), and getString(). * Implementations may also change the state to not writable when this occurs. *

    - * The state moves from writable to not writable once free() or any of the + * The state moves from writable to not writable once close(), free() or any of the * writing APIs are called: setBinaryStream(), setCharacterStream(), setResult(), and setString(). * Implementations may also change the state to not readable when this occurs. - * + *

    + * To release resources used by the {@code SQLXML} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code SQLXML} object has been closed, will result in a {@link SQLException} + * being thrown. *

    * All methods on the {@code SQLXML} interface must be fully implemented if the * JDBC driver supports the data type. @@ -188,21 +193,19 @@ import javax.xml.transform.Source; * @see javax.xml.xpath * @since 1.6 */ -public interface SQLXML +public interface SQLXML extends AutoCloseable { /** - * This method closes this object and releases the resources that it held. - * The SQL XML object becomes invalid and neither readable or writable - * when this method is called. + * Closes and releases the resources held by this {@code SQLXML} object. + *

    + * If the {@code SQLXML} object is already closed, then invoking this method + * has no effect. * - * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in a {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. * @throws SQLException if there is an error freeing the XML value. * @throws SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since 1.6 + * @see #close() */ void free() throws SQLException; @@ -424,4 +427,21 @@ public interface SQLXML */ T setResult(Class resultClass) throws SQLException; + /** + * Closes and releases the resources held by this {@code SQLXML} object. + *

    + * If the {@code SQLXML} object is already closed, then invoking this method + * has no effect. + * + * @throws SQLException if an error occurs releasing + * the SQLXML's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @implSpec The default implementation calls the {@link #free()} method. + * @see #free() + * @since 26 + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Statement.java b/src/java.sql/share/classes/java/sql/Statement.java index bb5a5cfd64d..4da510f6749 100644 --- a/src/java.sql/share/classes/java/sql/Statement.java +++ b/src/java.sql/share/classes/java/sql/Statement.java @@ -25,9 +25,6 @@ package java.sql; -import java.util.regex.Pattern; -import static java.util.stream.Collectors.joining; - /** *

    The object used for executing a static SQL statement * and returning the results it produces. @@ -1395,6 +1392,9 @@ public interface Statement extends Wrapper, AutoCloseable { * * * + * @implSpec + * The default implementation creates the literal as: + * {@code "'" + val.replace("'", "''") + "'"}. * @implNote * JDBC driver implementations may need to provide their own implementation * of this method in order to meet the requirements of the underlying @@ -1407,46 +1407,50 @@ public interface Statement extends Wrapper, AutoCloseable { * * @since 9 */ - default String enquoteLiteral(String val) throws SQLException { - return "'" + val.replace("'", "''") + "'"; + default String enquoteLiteral(String val) throws SQLException { + return SQLUtils.enquoteLiteral(val); } - - /** - * Returns a SQL identifier. If {@code identifier} is a simple SQL identifier: + /** + * Returns a {@link #isSimpleIdentifier(String) simple SQL identifier} or a + * delimited identifier. A delimited identifier represents the name of a + * database object such as a table, column, or view that is enclosed by a + * delimiter, which is typically a double quote as defined by the SQL standard. + *

    + * If {@code identifier} is a simple SQL identifier: *

      - *
    • Return the original value if {@code alwaysQuote} is - * {@code false}
    • - *
    • Return a delimited identifier if {@code alwaysQuote} is - * {@code true}
    • + *
    • If {@code alwaysDelimit} is {@code false}, return the original value
    • + *
    • if {@code alwaysDelimit} is {@code true}, enquote the original value + * and return as a delimited identifier
    • *
    * - * If {@code identifier} is not a simple SQL identifier, {@code identifier} will be - * enclosed in double quotes if not already present. If the datasource does - * not support double quotes for delimited identifiers, the - * identifier should be enclosed by the string returned from - * {@link DatabaseMetaData#getIdentifierQuoteString}. If the datasource - * does not support delimited identifiers, a - * {@code SQLFeatureNotSupportedException} should be thrown. + * If {@code identifier} is not a simple SQL identifier, the delimited + * {@code identifier} to be returned must be enclosed by the delimiter + * returned from {@link DatabaseMetaData#getIdentifierQuoteString}. If + * the datasource does not support delimited identifiers, a + * {@code SQLFeatureNotSupportedException} is thrown. *

    * A {@code SQLException} will be thrown if {@code identifier} contains any - * characters invalid in a delimited identifier or the identifier length is - * invalid for the datasource. + * invalid characters within a delimited identifier or the identifier length + * is invalid for the datasource. * * @implSpec * The default implementation uses the following criteria to * determine a valid simple SQL identifier: *

      *
    • The string is not enclosed in double quotes
    • - *
    • The first character is an alphabetic character from a through z, or - * from A through Z
    • - *
    • The name only contains alphanumeric characters or the character "_"
    • + *
    • The first character is an alphabetic character from a ({@code '\u005C0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters([0-9A-Za-z]) + * or the character "_"
    • *
    * * The default implementation will throw a {@code SQLException} if: *
      - *
    • {@code identifier} contains a {@code null} character or double quote and is not - * a simple SQL identifier.
    • + *
    • {@link DatabaseMetaData#getIdentifierQuoteString} does not return a + * double quote
    • + *
    • {@code identifier} contains a {@code null} character or double quote
    • *
    • The length of {@code identifier} is less than 1 or greater than 128 characters *
    *
    @@ -1455,7 +1459,7 @@ public interface Statement extends Wrapper, AutoCloseable { * * * identifier - * alwaysQuote + * alwaysDelimit * Result * * @@ -1485,6 +1489,16 @@ public interface Statement extends Wrapper, AutoCloseable { * "Bruce Wayne" * * + * "select" + * false + * "select" + * + * + * "select" + * true + * "select" + * + * * GoodDay$ * false * "GoodDay$" @@ -1507,8 +1521,8 @@ public interface Statement extends Wrapper, AutoCloseable { * of this method in order to meet the requirements of the underlying * datasource. * @param identifier a SQL identifier - * @param alwaysQuote indicates if a simple SQL identifier should be - * returned as a quoted identifier + * @param alwaysDelimit indicates if a simple SQL identifier should be + * returned as a delimited identifier * @return A simple SQL identifier or a delimited identifier * @throws SQLException if identifier is not a valid identifier * @throws SQLFeatureNotSupportedException if the datasource does not support @@ -1517,36 +1531,43 @@ public interface Statement extends Wrapper, AutoCloseable { * * @since 9 */ - default String enquoteIdentifier(String identifier, boolean alwaysQuote) throws SQLException { - int len = identifier.length(); - if (len < 1 || len > 128) { - throw new SQLException("Invalid name"); - } - if (Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*").matcher(identifier).matches()) { - return alwaysQuote ? "\"" + identifier + "\"" : identifier; - } - if (identifier.matches("^\".+\"$")) { - identifier = identifier.substring(1, len - 1); - } - if (Pattern.compile("[^\u0000\"]+").matcher(identifier).matches()) { - return "\"" + identifier + "\""; - } else { - throw new SQLException("Invalid name"); - } + default String enquoteIdentifier(String identifier, boolean alwaysDelimit) throws SQLException { + return getConnection().enquoteIdentifier(identifier,alwaysDelimit); } /** - * Retrieves whether {@code identifier} is a simple SQL identifier. + * Returns whether {@code identifier} is a simple SQL identifier. + * A simple SQL identifier is referred to as regular (or ordinary) identifier + * within the SQL standard. A regular identifier represents the name of a database + * object such as a table, column, or view. + *

    + * The rules for a regular Identifier are: + *

      + *
    • The first character is an alphabetic character from a ({@code '\u005Cu0061'}) + * through z ({@code '\u005Cu007A'}), or from A ({@code '\u005Cu0041'}) + * through Z ({@code '\u005Cu005A'})
    • + *
    • The name only contains alphanumeric characters([0-9A-Za-z]) or the + * character "_"
    • + *
    • It cannot be a SQL reserved word
    • + *
    + *

    + * A datasource may have additional rules for a regular identifier such as: + *

      + *
    • Supports additional characters within the name based on + * the locale being used
    • + *
    • Supports a different maximum length for the identifier
    • + *
    * * @implSpec The default implementation uses the following criteria to * determine a valid simple SQL identifier: *
      - *
    • The string is not enclosed in double quotes
    • + *
    • The identifier is not enclosed in double quotes
    • *
    • The first character is an alphabetic character from a through z, or * from A through Z
    • - *
    • The string only contains alphanumeric characters or the character - * "_"
    • - *
    • The string is between 1 and 128 characters in length inclusive
    • + *
    • The identifier only contains alphanumeric characters([0-9A-Za-z]) + * or the character "_"
    • + *
    • The identifier is not a SQL reserved word
    • + *
    • The identifier is between 1 and 128 characters in length inclusive
    • *
    * *
    @@ -1583,6 +1604,13 @@ public interface Statement extends Wrapper, AutoCloseable { * "Hello"World" * false * + * + * "select" + * false + * + * "from" + * false + * * * *
    @@ -1590,16 +1618,14 @@ public interface Statement extends Wrapper, AutoCloseable { * implementation of this method in order to meet the requirements of the * underlying datasource. * @param identifier a SQL identifier - * @return true if a simple SQL identifier, false otherwise + * @return true if a simple SQL identifier, false otherwise * @throws NullPointerException if identifier is {@code null} * @throws SQLException if a database access error occurs * * @since 9 */ default boolean isSimpleIdentifier(String identifier) throws SQLException { - int len = identifier.length(); - return len >= 1 && len <= 128 - && Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*").matcher(identifier).matches(); + return SQLUtils.isSimpleIdentifier(identifier); } /** @@ -1628,7 +1654,10 @@ public interface Statement extends Wrapper, AutoCloseable { * * *
    - * @implNote + * @implSpec + * The default implementation creates the literal as: + * {@code "N'" + val.replace("'", "''") + "'"}. + * @implNote * JDBC driver implementations may need to provide their own implementation * of this method in order to meet the requirements of the underlying * datasource. An implementation of enquoteNCharLiteral may accept a different @@ -1643,7 +1672,7 @@ public interface Statement extends Wrapper, AutoCloseable { * * @since 9 */ - default String enquoteNCharLiteral(String val) throws SQLException { - return "N'" + val.replace("'", "''") + "'"; + default String enquoteNCharLiteral(String val) throws SQLException { + return SQLUtils.enquoteNCharLiteral(val); } } diff --git a/src/java.sql/share/classes/java/sql/Timestamp.java b/src/java.sql/share/classes/java/sql/Timestamp.java index a91ab7210c5..c550291bb95 100644 --- a/src/java.sql/share/classes/java/sql/Timestamp.java +++ b/src/java.sql/share/classes/java/sql/Timestamp.java @@ -54,10 +54,7 @@ import java.time.LocalDateTime; * because the nanos component of a date is unknown. * As a result, the {@code Timestamp.equals(Object)} * method is not symmetric with respect to the - * {@code java.util.Date.equals(Object)} - * method. Also, the {@code hashCode} method uses the underlying - * {@code java.util.Date} - * implementation and therefore does not include nanos in its computation. + * {@code java.util.Date.equals(Object)} method. *

    * Due to the differences between the {@code Timestamp} class * and the {@code java.util.Date} @@ -465,10 +462,15 @@ public class Timestamp extends java.util.Date { } /** - * {@inheritDoc} + * Returns a hash code value for this Timestamp. The result is the + * exclusive OR of the two halves of the primitive {@code long} + * value returned by the {@link #getTime} method. That is, + * the hash code is the value of the expression: + * {@snippet : + * (int)(this.getTime()^(this.getTime() >>> 32)) + * } * - * The {@code hashCode} method uses the underlying {@code java.util.Date} - * implementation and therefore does not include nanos in its computation. + * @return a hash code value for this Timestamp. * */ @Override diff --git a/src/java.sql/share/classes/java/sql/Types.java b/src/java.sql/share/classes/java/sql/Types.java index 2b3b571647b..778d782ddaf 100644 --- a/src/java.sql/share/classes/java/sql/Types.java +++ b/src/java.sql/share/classes/java/sql/Types.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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 @@ -339,6 +339,27 @@ public class Types { */ public static final int TIMESTAMP_WITH_TIMEZONE = 2014; + + //--------------------------JDBC 4.5 ----------------------------- + + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code DECFLOAT}. + * + * @since 26 + */ + public static final int DECFLOAT = 2015; + + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code JSON}. + * + * @since 26 + */ + public static final int JSON = 2016; + // Prevent instantiation private Types() {} } diff --git a/src/java.sql/share/classes/java/sql/package-info.java b/src/java.sql/share/classes/java/sql/package-info.java index 495119effac..64b23dba76f 100644 --- a/src/java.sql/share/classes/java/sql/package-info.java +++ b/src/java.sql/share/classes/java/sql/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,20 +38,22 @@ * use and update data from a spread sheet, flat file, or any other tabular * data source. * - *

    What the JDBC 4.3 API Includes

    - * The JDBC 4.3 API includes both + *

    What the JDBC 4.5 API Includes

    + * The JDBC 4.5 API includes both * the {@code java.sql} package, referred to as the JDBC core API, * and the {@code javax.sql} package, referred to as the JDBC Optional * Package API. This complete JDBC API - * is included in the Java Standard Edition (Java SE), version 7. + * is included in the Java Standard Edition (Java SE). * The {@code javax.sql} package extends the functionality of the JDBC API * from a client-side API to a server-side API, and it is an essential part * of the Java Enterprise Edition * (Java EE) technology. * *

    Versions

    - * The JDBC 4.3 API incorporates all of the previous JDBC API versions: + * The JDBC 4.5 API incorporates all the previous JDBC API versions: *
      + *
    • The JDBC 4.4 API
    • + *
    • The JDBC 4.3 API
    • *
    • The JDBC 4.2 API
    • *
    • The JDBC 4.1 API
    • *
    • The JDBC 4.0 API
    • @@ -70,6 +72,10 @@ * Javadoc comments for the JDBC API, * they indicate the following: *
        + *
      • Since 26 -- new in the JDBC 4.5 API and part of the Java SE platform, + * version 26
      • + *
      • Since 24 -- new in the JDBC 4.4 API and part of the Java SE platform, + * version 24
      • *
      • Since 9 -- new in the JDBC 4.3 API and part of the Java SE platform, * version 9
      • *
      • Since 1.8 -- new in the JDBC 4.2 API and part of the Java SE platform, @@ -126,6 +132,7 @@ *
      • {@code Blob} interface -- mapping for SQL {@code BLOB} *
      • {@code Clob} interface -- mapping for SQL {@code CLOB} *
      • {@code Date} class -- mapping for SQL {@code DATE} + *
      • {@code JDBCType} class -- provides enum constants for SQL types *
      • {@code NClob} interface -- mapping for SQL {@code NCLOB} *
      • {@code Ref} interface -- mapping for SQL {@code REF} *
      • {@code RowId} interface -- mapping for SQL {@code ROWID} @@ -166,6 +173,26 @@ *
      *
    * + *

    {@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 4.5 API

    + *
      + *
    • The interfaces {@code Array}, {@code Blob}, {@code Clob}, {@code NClob} + * and {@code SQLXML} now extend the {@code AutoCloseable} interface and + * include a default {@code close} method implementation
    • + *
    • Added support to {@code Connection} for enquoting literals + * and simple identifiers
    • + *
    • {@code SQLPermissions} has been deprecated for removal
    • + *
    • The SQL Types {@code JSON} and {@code DECFLOAT} have been added to + * {@code JDBCType} and {@code Types}
    • + *
    + *

    {@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 4.4 API

    + *
      + *
    • Remove mention of {@code SecurityManager} and {@code SecurityException} + * as the {@code SecurityManager} is no longer supported
    • + *
    • {@code SQLPermissions} can no longer be used to control access to + * resources as the {@code SecurityManager} is no longer supported
    • + *
    • Added support to {@code Connection} for enquoting literals + * and simple identifiers
    • + *
    *

    {@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 4.3 API

    *
      *
    • Added {@code Sharding} support
    • @@ -232,7 +259,6 @@ * *
    * - * *

    {@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 3.0 API

    *
      *
    • Pooled statements -- reuse of statements associated with a pooled @@ -288,7 +314,6 @@ * handling and passing data *
    * - * *

    Custom Mapping of UDTs

    * A user-defined type (UDT) defined in SQL can be mapped to a class in the Java * programming language. An SQL structured type or an SQL {@code DISTINCT} @@ -317,7 +342,7 @@ *

    Package Specification

    * * * *

    Related Documentation

    @@ -326,7 +351,6 @@ *
  • * Lesson:JDBC Basics(The Java Tutorials > JDBC Database Access) * - *
  • JDBC API Tutorial and Reference, Third Edition” * * @since 1.1 */ diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index 2eca26de838..22ee2393a02 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -413,7 +413,18 @@ public class JavacTrees extends DocTrees { } if (ref.qualifierExpression == null) { - tsym = env.enclClass.sym; + // Resolve target for unqualified reference based on declaring element + tsym = switch (path.getLeaf().getKind()) { + case PACKAGE -> env.toplevel.packge; + case MODULE -> env.toplevel.modle; + case COMPILATION_UNIT -> + // Treat unqualified reference in legacy package.html as package reference. + // Unqualified references in doc-files only need to work locally, so null is fine. + path.getCompilationUnit().getSourceFile().isNameCompatible("package", JavaFileObject.Kind.HTML) + ? env.toplevel.packge + : null; + default -> env.enclClass.sym; // Class or class member reference + }; memberName = (Name) ref.memberName; } else { // Check if qualifierExpression is a type or package, using the methods javac provides. @@ -470,8 +481,15 @@ public class JavacTrees extends DocTrees { } } - if (memberName == null) + if (memberName == null) { return tsym; + } else if (tsym == null || tsym.getKind() == ElementKind.PACKAGE || tsym.getKind() == ElementKind.MODULE) { + return null; // Non-null member name in non-class context + } + + if (tsym.type.isPrimitive()) { + return null; + } final List paramTypes; if (ref.paramTypes == null) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java index 063d37be4e2..84a823f785f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java @@ -158,6 +158,11 @@ public enum Source { * 26, tbd */ JDK26("26"), + + /** + * 27, tbd + */ + JDK27("27"), ; // Reduce code churn when appending new constants private static final Context.Key sourceKey = new Context.Key<>(); @@ -210,6 +215,7 @@ public enum Source { public Target requiredTarget() { return switch(this) { + case JDK27 -> Target.JDK1_27; case JDK26 -> Target.JDK1_26; case JDK25 -> Target.JDK1_25; case JDK24 -> Target.JDK1_24; @@ -277,6 +283,7 @@ public enum Source { JAVA_BASE_TRANSITIVE(JDK25, Fragments.FeatureJavaBaseTransitive, DiagKind.PLURAL), PRIVATE_MEMBERS_IN_PERMITS_CLAUSE(JDK19), ERASE_POLY_SIG_RETURN_TYPE(JDK24), + CAPTURE_MREF_RETURN_TYPE(JDK26), ; enum DiagKind { @@ -365,6 +372,7 @@ public enum Source { case JDK24 -> RELEASE_24; case JDK25 -> RELEASE_25; case JDK26 -> RELEASE_26; + case JDK27 -> RELEASE_27; default -> null; }; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java index 0b97b119119..b2771556eb2 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java @@ -26,7 +26,7 @@ package com.sun.tools.javac.code; import com.sun.source.tree.Tree.Kind; - +import java.lang.runtime.ExactConversionsSupport; import javax.lang.model.type.TypeKind; import static com.sun.tools.javac.code.TypeTag.NumericClasses.*; @@ -186,6 +186,10 @@ public enum TypeTag { return (this.numericClass & tag.superClasses) != 0; } + public boolean isNumeric() { + return this.numericClass != 0; + } + /** Returns the number of type tags. */ public static int getTypeTagCount() { @@ -247,11 +251,11 @@ public enum TypeTag { case BOOLEAN: return 0 <= value && value <= 1; case BYTE: - return Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE; + return ExactConversionsSupport.isIntToByteExact(value); case CHAR: - return Character.MIN_VALUE <= value && value <= Character.MAX_VALUE; + return ExactConversionsSupport.isIntToCharExact(value); case SHORT: - return Short.MIN_VALUE <= value && value <= Short.MAX_VALUE; + return ExactConversionsSupport.isIntToShortExact(value); case INT: return true; default: diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java index ffd304c18a2..3f3eb1f9623 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java @@ -26,6 +26,7 @@ package com.sun.tools.javac.code; import java.lang.ref.SoftReference; +import java.lang.runtime.ExactConversionsSupport; import java.util.HashSet; import java.util.HashMap; import java.util.Locale; @@ -3971,7 +3972,7 @@ public class Types { * Return the minimum types of a closure, suitable for computing * compoundMin or glb. */ - private List closureMin(List cl) { + public List closureMin(List cl) { ListBuffer classes = new ListBuffer<>(); ListBuffer interfaces = new ListBuffer<>(); Set toSkip = new HashSet<>(); @@ -5086,46 +5087,128 @@ public class Types { } // - // - /** Check unconditionality between any combination of reference or primitive types. + // + /** Check type-based unconditional exactness between any combination of + * reference or primitive types according to JLS 5.7.2. * - * Rules: - * an identity conversion - * a widening reference conversion - * a widening primitive conversion (delegates to `checkUnconditionallyExactPrimitives`) - * a boxing conversion - * a boxing conversion followed by a widening reference conversion + * The following are unconditionally exact regardless of the input + * expression: + * + * - an identity conversion + * - a widening reference conversion + * - an exact widening primitive conversion + * - a boxing conversion + * - a boxing conversion followed by a widening reference conversion * * @param source Source primitive or reference type * @param target Target primitive or reference type */ - public boolean isUnconditionallyExact(Type source, Type target) { + public boolean isUnconditionallyExactTypeBased(Type source, Type target) { if (isSameType(source, target)) { return true; } - return target.isPrimitive() - ? isUnconditionallyExactPrimitives(source, target) - : isSubtype(boxedTypeOrType(erasure(source)), target); + if (target.isPrimitive()) { + if (source.isPrimitive() && + ((source.getTag().isStrictSubRangeOf(target.getTag())) && + !((source.hasTag(BYTE) && target.hasTag(CHAR)) || + (source.hasTag(INT) && target.hasTag(FLOAT)) || + (source.hasTag(LONG) && (target.hasTag(DOUBLE) || target.hasTag(FLOAT)))))) return true; + else { + return false; + } + } else { + return isSubtype(boxedTypeOrType(erasure(source)), target); + } } - /** Check unconditionality between primitive types. + /** Check value-based unconditional exactness between any combination of + * reference or primitive types for the value of a constant expression + * according to JLS 5.7.2. * - * - widening from one integral type to another, - * - widening from one floating point type to another, - * - widening from byte, short, or char to a floating point type, - * - widening from int to double. + * The following can be unconditionally exact if the source primitive is a + * constant expression and the conversions is exact for that constant + * expression: * - * @param selectorType Type of selector - * @param targetType Target type + * - a narrowing primitive conversion + * - a widening and narrowing primitive conversion + * - a widening primitive conversion that is not exact + * + * @param source Source primitive or reference type, should be a numeric value + * @param target Target primitive or reference type */ - public boolean isUnconditionallyExactPrimitives(Type selectorType, Type targetType) { - return isSameType(selectorType, targetType) || - (selectorType.isPrimitive() && targetType.isPrimitive()) && - ((selectorType.getTag().isStrictSubRangeOf(targetType.getTag())) && - !((selectorType.hasTag(BYTE) && targetType.hasTag(CHAR)) || - (selectorType.hasTag(INT) && targetType.hasTag(FLOAT)) || - (selectorType.hasTag(LONG) && (targetType.hasTag(DOUBLE) || targetType.hasTag(FLOAT))))); + public boolean isUnconditionallyExactValueBased(Type source, Type target) { + if (!(source.constValue() instanceof Number value) || !target.getTag().isNumeric()) return false; + + switch (source.getTag()) { + case BYTE: + switch (target.getTag()) { + case CHAR: return ExactConversionsSupport.isIntToCharExact(value.intValue()); + } + break; + case CHAR: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isIntToByteExact(value.intValue()); + case SHORT: return ExactConversionsSupport.isIntToShortExact(value.intValue()); + } + break; + case SHORT: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isIntToByteExact(value.intValue()); + case CHAR: return ExactConversionsSupport.isIntToCharExact(value.intValue()); + } + break; + case INT: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isIntToByteExact(value.intValue()); + case CHAR: return ExactConversionsSupport.isIntToCharExact(value.intValue()); + case SHORT: return ExactConversionsSupport.isIntToShortExact(value.intValue()); + case FLOAT: return ExactConversionsSupport.isIntToFloatExact(value.intValue()); + } + break; + case FLOAT: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isFloatToByteExact(value.floatValue()); + case CHAR: return ExactConversionsSupport.isFloatToCharExact(value.floatValue()); + case SHORT: return ExactConversionsSupport.isFloatToShortExact(value.floatValue()); + case INT: return ExactConversionsSupport.isFloatToIntExact(value.floatValue()); + case LONG: return ExactConversionsSupport.isFloatToLongExact(value.floatValue()); + } + break; + case LONG: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isLongToByteExact(value.longValue()); + case CHAR: return ExactConversionsSupport.isLongToCharExact(value.longValue()); + case SHORT: return ExactConversionsSupport.isLongToShortExact(value.longValue()); + case INT: return ExactConversionsSupport.isLongToIntExact(value.longValue()); + case FLOAT: return ExactConversionsSupport.isLongToFloatExact(value.longValue()); + case DOUBLE: return ExactConversionsSupport.isLongToDoubleExact(value.longValue()); + } + break; + case DOUBLE: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isDoubleToByteExact(value.doubleValue()); + case CHAR: return ExactConversionsSupport.isDoubleToCharExact(value.doubleValue()); + case SHORT: return ExactConversionsSupport.isDoubleToShortExact(value.doubleValue()); + case INT: return ExactConversionsSupport.isDoubleToIntExact(value.doubleValue()); + case FLOAT: return ExactConversionsSupport.isDoubleToFloatExact(value.doubleValue()); + case LONG: return ExactConversionsSupport.isDoubleToLongExact(value.doubleValue()); + } + break; + } + return true; + } + + /** Check both type or value-based unconditional exactness between any + * combination of reference or primitive types for the value of a constant + * expression according to JLS 5.7.2. + * + * @param source Source primitive or reference type, should be a numeric value + * @param target Target primitive or reference type + */ + public boolean isUnconditionallyExactCombined(Type currentType, Type testType) { + return isUnconditionallyExactTypeBased(currentType, testType) || + (currentType.constValue() instanceof Number && isUnconditionallyExactValueBased(currentType, testType)); } // 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 1465ea652b1..3f72ada94e8 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 @@ -124,6 +124,7 @@ public class Attr extends JCTree.Visitor { final ArgumentAttr argumentAttr; final MatchBindingsComputer matchBindingsComputer; final AttrRecover attrRecover; + final boolean captureMRefReturnType; public static Attr instance(Context context) { Attr instance = context.get(attrKey); @@ -175,6 +176,7 @@ public class Attr extends JCTree.Visitor { Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF.allowedInSource(source); sourceName = source.name; useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning"); + captureMRefReturnType = Source.Feature.CAPTURE_MREF_RETURN_TYPE.allowedInSource(source); statInfo = new ResultInfo(KindSelector.NIL, Type.noType); varAssignmentInfo = new ResultInfo(KindSelector.ASG, Type.noType); @@ -375,7 +377,7 @@ public class Attr extends JCTree.Visitor { @Override @DefinedBy(Api.COMPILER_TREE) public Symbol visitMemberSelect(MemberSelectTree node, Env env) { Symbol site = visit(node.getExpression(), env); - if (site.kind == ERR || site.kind == ABSENT_TYP || site.kind == HIDDEN) + if (site == null || site.kind == ERR || site.kind == ABSENT_TYP || site.kind == HIDDEN) return site; Name name = (Name)node.getIdentifier(); if (site.kind == PCK) { @@ -1859,7 +1861,7 @@ public class Attr extends JCTree.Visitor { boolean unconditional = unguarded && !patternType.isErroneous() && - types.isUnconditionallyExact(seltype, patternType); + types.isUnconditionallyExactTypeBased(seltype, patternType); if (unconditional) { if (hasUnconditionalPattern) { log.error(pat.pos(), Errors.DuplicateUnconditionalPattern); @@ -3832,9 +3834,10 @@ public class Attr extends JCTree.Visitor { } if (!returnType.hasTag(VOID) && !resType.hasTag(VOID)) { + Type capturedResType = captureMRefReturnType ? types.capture(resType) : resType; if (resType.isErroneous() || - new FunctionalReturnContext(checkContext).compatible(resType, returnType, - checkContext.checkWarner(tree, resType, returnType))) { + new FunctionalReturnContext(checkContext).compatible(capturedResType, returnType, + checkContext.checkWarner(tree, capturedResType, returnType))) { incompatibleReturnType = null; } } @@ -3998,6 +4001,7 @@ public class Attr extends JCTree.Visitor { operator.type.getReturnType(), owntype); chk.checkLossOfPrecision(tree.rhs.pos(), operand, owntype); + chk.checkOutOfRangeShift(tree.rhs.pos(), operator, operand); } result = check(tree, owntype, KindSelector.VAL, resultInfo); } @@ -4088,6 +4092,7 @@ public class Attr extends JCTree.Visitor { } chk.checkDivZero(tree.rhs.pos(), operator, right); + chk.checkOutOfRangeShift(tree.rhs.pos(), operator, right); } result = check(tree, owntype, KindSelector.VAL, resultInfo); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index da7db138604..94b14f3122f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -28,7 +28,6 @@ package com.sun.tools.javac.comp; import java.util.*; import java.util.function.BiConsumer; import java.util.function.BiPredicate; -import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.function.ToIntBiFunction; @@ -167,6 +166,7 @@ public class Check { allowModules = Feature.MODULES.allowedInSource(source); allowRecords = Feature.RECORDS.allowedInSource(source); allowSealed = Feature.SEALED_CLASSES.allowedInSource(source); + allowPrimitivePatterns = preview.isEnabled() && Feature.PRIMITIVE_PATTERNS.allowedInSource(source); } /** Character for synthetic names @@ -190,6 +190,10 @@ public class Check { */ private final boolean allowSealed; + /** Are primitive patterns allowed + */ + private final boolean allowPrimitivePatterns; + /** Whether to force suppression of deprecation and preview warnings. * This happens when attributing import statements for JDK 9+. * @see Feature#DEPRECATION_ON_IMPORT @@ -4041,6 +4045,37 @@ public class Check { } } + /** + * Check for bit shifts using an out-of-range bit count. + * @param pos Position for error reporting. + * @param operator The operator for the expression + * @param operand The right hand operand for the expression + */ + void checkOutOfRangeShift(final DiagnosticPosition pos, Symbol operator, Type operand) { + if (operand.constValue() instanceof Number shiftAmount) { + Type targetType; + int maximumShift; + switch (((OperatorSymbol)operator).opcode) { + case ByteCodes.ishl, ByteCodes.ishr, ByteCodes.iushr, ByteCodes.ishll, ByteCodes.ishrl, ByteCodes.iushrl -> { + targetType = syms.intType; + maximumShift = 0x1f; + } + case ByteCodes.lshl, ByteCodes.lshr, ByteCodes.lushr, ByteCodes.lshll, ByteCodes.lshrl, ByteCodes.lushrl -> { + targetType = syms.longType; + maximumShift = 0x3f; + } + default -> { + return; + } + } + long specifiedShift = shiftAmount.longValue(); + if (specifiedShift > maximumShift || specifiedShift < -maximumShift) { + int actualShift = (int)specifiedShift & (maximumShift - 1); + log.warning(pos, LintWarnings.BitShiftOutOfRange(targetType, specifiedShift, actualShift)); + } + } + } + /** * Check for possible loss of precission * @param pos Position for error reporting. @@ -4733,21 +4768,26 @@ public class Check { JCCase testCase = caseAndLabel.fst; JCCaseLabel testCaseLabel = caseAndLabel.snd; Type testType = labelType(testCaseLabel); + + // an unconditional pattern cannot be followed by any other label + if (allowPrimitivePatterns && unconditionalCaseLabel == testCaseLabel && unconditionalCaseLabel != label) { + log.error(label.pos(), Errors.PatternDominated); + continue; + } + boolean dominated = false; - if (types.isUnconditionallyExact(currentType, testType) && - !currentType.hasTag(ERROR) && !testType.hasTag(ERROR)) { - //the current label is potentially dominated by the existing (test) label, check: - if (label instanceof JCConstantCaseLabel) { - dominated |= !(testCaseLabel instanceof JCConstantCaseLabel) && + if (!currentType.hasTag(ERROR) && !testType.hasTag(ERROR)) { + // the current label is potentially dominated by the existing (test) label, check: + if (types.isUnconditionallyExactCombined(currentType, testType) && + label instanceof JCConstantCaseLabel) { + dominated = !(testCaseLabel instanceof JCConstantCaseLabel) && TreeInfo.unguardedCase(testCase); } else if (label instanceof JCPatternCaseLabel patternCL && testCaseLabel instanceof JCPatternCaseLabel testPatternCaseLabel && (testCase.equals(c) || TreeInfo.unguardedCase(testCase))) { - dominated = patternDominated(testPatternCaseLabel.pat, - patternCL.pat); + dominated = patternDominated(testPatternCaseLabel.pat, patternCL.pat); } } - if (dominated) { log.error(label.pos(), Errors.PatternDominated); } @@ -4767,7 +4807,7 @@ public class Check { private boolean patternDominated(JCPattern existingPattern, JCPattern currentPattern) { Type existingPatternType = types.erasure(existingPattern.type); Type currentPatternType = types.erasure(currentPattern.type); - if (!types.isUnconditionallyExact(currentPatternType, existingPatternType)) { + if (!types.isUnconditionallyExactTypeBased(currentPatternType, existingPatternType)) { return false; } if (currentPattern instanceof JCBindingPattern || diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java index 3b66ac010cf..bbc330832f3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java @@ -39,6 +39,7 @@ import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.code.Kinds.Kind; import com.sun.tools.javac.code.Type.TypeVar; +import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.function.Predicate; @@ -60,6 +61,7 @@ public class ExhaustivenessComputer { private final Types types; private final Check chk; private final Infer infer; + private final Map, Boolean> isSubtypeCache = new HashMap<>(); public static ExhaustivenessComputer instance(Context context) { ExhaustivenessComputer instance = context.get(exhaustivenessKey); @@ -120,6 +122,7 @@ public class ExhaustivenessComputer { } } Set patterns = patternSet; + Set> seenFallback = new HashSet<>(); boolean useHashes = true; try { boolean repeat = true; @@ -141,7 +144,7 @@ public class ExhaustivenessComputer { //but hashing in reduceNestedPatterns will not allow that //disable the use of hashing, and use subtyping in //reduceNestedPatterns to handle situations like this: - repeat = useHashes; + repeat = useHashes && seenFallback.add(updatedPatterns); useHashes = false; } else { //if a reduction happened, make sure hashing in reduceNestedPatterns @@ -154,6 +157,8 @@ public class ExhaustivenessComputer { } catch (CompletionFailure cf) { chk.completionError(selector.pos(), cf); return true; //error recovery + } finally { + isSubtypeCache.clear(); } } @@ -211,10 +216,9 @@ public class ExhaustivenessComputer { //if a binding pattern for clazz already exists, no need to analyze it again: !existingBindings.contains(clazz)) { //do not reduce to types unrelated to the selector type: - Type clazzErasure = types.erasure(clazz.type); + Type clazzType = clazz.type; if (components(selectorType).stream() - .map(types::erasure) - .noneMatch(c -> types.isSubtype(clazzErasure, c))) { + .noneMatch(c -> isSubtypeErasure(clazzType, c))) { continue; } @@ -238,18 +242,18 @@ public class ExhaustivenessComputer { //cover using bpOther: //all types that are permitted subtypes of bpOther's type: - pendingPermitted.removeIf(pending -> types.isSubtype(types.erasure(pending.type), - types.erasure(bpOther.type))); + pendingPermitted.removeIf(pending -> isSubtypeErasure(pending.type, + bpOther.type)); if (bpOther.type.tsym.isAbstract()) { //all types that are in a diamond hierarchy with bpOther's type //i.e. there's a common subtype of the given type and bpOther's type: Predicate check = pending -> permitted.stream() - .filter(perm -> types.isSubtype(types.erasure(perm.type), - types.erasure(bpOther.type))) - .filter(perm -> types.isSubtype(types.erasure(perm.type), - types.erasure(pending.type))) + .filter(perm -> isSubtypeErasure(perm.type, + bpOther.type)) + .filter(perm -> isSubtypeErasure(perm.type, + pending.type)) .findAny() .isPresent(); @@ -374,30 +378,15 @@ public class ExhaustivenessComputer { join.append(rpOne); - NEXT_PATTERN: for (int nextCandidate = 0; - nextCandidate < candidatesArr.length; - nextCandidate++) { + for (int nextCandidate = 0; nextCandidate < candidatesArr.length; nextCandidate++) { if (firstCandidate == nextCandidate) { continue; } RecordPattern rpOther = candidatesArr[nextCandidate]; - if (rpOne.recordType.tsym == rpOther.recordType.tsym) { - for (int i = 0; i < rpOne.nested.length; i++) { - if (i != mismatchingCandidate) { - if (!rpOne.nested[i].equals(rpOther.nested[i])) { - if (useHashes || - //when not using hashes, - //check if rpOne.nested[i] is - //a subtype of rpOther.nested[i]: - !(rpOne.nested[i] instanceof BindingPattern bpOne) || - !(rpOther.nested[i] instanceof BindingPattern bpOther) || - !types.isSubtype(types.erasure(bpOne.type), types.erasure(bpOther.type))) { - continue NEXT_PATTERN; - } - } - } - } + + if (rpOne.recordType.tsym == rpOther.recordType.tsym && + nestedComponentsEquivalent(rpOne, rpOther, mismatchingCandidate, useHashes)) { join.append(rpOther); } } @@ -418,9 +407,11 @@ public class ExhaustivenessComputer { PatternDescription[] newNested = Arrays.copyOf(rpOne.nested, rpOne.nested.length); newNested[mismatchingCandidateFin] = nested; - current.add(new RecordPattern(rpOne.recordType(), + RecordPattern nue = new RecordPattern(rpOne.recordType(), rpOne.fullComponentTypes(), - newNested)); + newNested, + new HashSet<>(join)); + current.add(nue); } } } @@ -437,6 +428,70 @@ public class ExhaustivenessComputer { return patterns; } + /* Returns true if all nested components of existing and candidate are + * equivalent (if useHashes == true), or "substitutable" (if useHashes == false). + * A candidate pattern is "substitutable" if it is a binding pattern, and: + * - it's type is a supertype of the existing pattern's type + * - it was produced by a reduction from a record pattern that is equivalent to + * the existing pattern + */ + private boolean nestedComponentsEquivalent(RecordPattern existing, + RecordPattern candidate, + int mismatchingCandidate, + boolean useHashes) { + NEXT_NESTED: + for (int i = 0; i < existing.nested.length; i++) { + if (i != mismatchingCandidate) { + if (!existing.nested[i].equals(candidate.nested[i])) { + if (useHashes) { + return false; + } + //when not using hashes, + //check if rpOne.nested[i] is + //a subtype of rpOther.nested[i]: + if (!(candidate.nested[i] instanceof BindingPattern nestedCandidate)) { + return false; + } + if (existing.nested[i] instanceof BindingPattern nestedExisting) { + if (!isSubtypeErasure(nestedExisting.type, nestedCandidate.type)) { + return false; + } + } else if (existing.nested[i] instanceof RecordPattern nestedExisting) { + java.util.List pendingReplacedPatterns = + new ArrayList<>(nestedCandidate.sourcePatterns()); + + while (!pendingReplacedPatterns.isEmpty()) { + PatternDescription currentReplaced = pendingReplacedPatterns.removeLast(); + + if (nestedExisting.equals(currentReplaced)) { + //candidate.nested[i] is substitutable for existing.nested[i] + //continue with the next nested pattern: + continue NEXT_NESTED; + } + + pendingReplacedPatterns.addAll(currentReplaced.sourcePatterns()); + } + + return false; + } else { + return false; + } + } + } + } + + return true; + } + + /*The same as types.isSubtype(types.erasure(t), types.erasure(s)), but cached. + */ + private boolean isSubtypeErasure(Type t, Type s) { + Pair key = Pair.of(t, s); + + return isSubtypeCache.computeIfAbsent(key, _ -> + types.isSubtype(types.erasure(t), types.erasure(s))); + } + /* In the set of patterns, find those for which, given: * $record($nested1, $nested2, ...) * all the $nestedX pattern cover the given record component, @@ -480,9 +535,11 @@ public class ExhaustivenessComputer { covered &= checkCovered(componentType[i], List.of(newNested)); } if (covered) { - return new BindingPattern(rpOne.recordType); + PatternDescription pd = new BindingPattern(rpOne.recordType, Set.of(pattern)); + return pd; } else if (reducedNestedPatterns != null) { - return new RecordPattern(rpOne.recordType, rpOne.fullComponentTypes(), reducedNestedPatterns); + PatternDescription pd = new RecordPattern(rpOne.recordType, rpOne.fullComponentTypes(), reducedNestedPatterns, Set.of(pattern)); + return pd; } } return pattern; @@ -511,13 +568,15 @@ public class ExhaustivenessComputer { Type pattype = types.erasure(bp.type); return seltype.isPrimitive() ? - types.isUnconditionallyExact(seltype, pattype) : - (bp.type.isPrimitive() && types.isUnconditionallyExact(types.unboxedType(seltype), bp.type)) || types.isSubtype(seltype, pattype); + types.isUnconditionallyExactTypeBased(seltype, pattype) : + (bp.type.isPrimitive() && types.isUnconditionallyExactTypeBased(types.unboxedType(seltype), bp.type)) || types.isSubtype(seltype, pattype); } return false; } - sealed interface PatternDescription { } + sealed interface PatternDescription { + public Set sourcePatterns(); + } public PatternDescription makePatternDescription(Type selectorType, JCPattern pattern) { if (pattern instanceof JCBindingPattern binding) { Type type = !selectorType.isPrimitive() && types.isSubtype(selectorType, binding.type) @@ -552,7 +611,12 @@ public class ExhaustivenessComputer { throw Assert.error(); } } - record BindingPattern(Type type) implements PatternDescription { + record BindingPattern(Type type, Set sourcePatterns) implements PatternDescription { + + public BindingPattern(Type type) { + this(type, Set.of()); + } + @Override public int hashCode() { return type.tsym.hashCode(); @@ -567,10 +631,14 @@ public class ExhaustivenessComputer { return type.tsym + " _"; } } - record RecordPattern(Type recordType, int _hashCode, Type[] fullComponentTypes, PatternDescription... nested) implements PatternDescription { + record RecordPattern(Type recordType, int _hashCode, Type[] fullComponentTypes, PatternDescription[] nested, Set sourcePatterns) implements PatternDescription { public RecordPattern(Type recordType, Type[] fullComponentTypes, PatternDescription[] nested) { - this(recordType, hashCode(-1, recordType, nested), fullComponentTypes, nested); + this(recordType, fullComponentTypes, nested, Set.of()); + } + + public RecordPattern(Type recordType, Type[] fullComponentTypes, PatternDescription[] nested, Set sourcePatterns) { + this(recordType, hashCode(-1, recordType, nested), fullComponentTypes, nested, sourcePatterns); } @Override diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java index aee7f0afe39..2db3435a382 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java @@ -36,7 +36,6 @@ import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; import com.sun.tools.javac.main.Option.PkgInfo; import com.sun.tools.javac.resources.CompilerProperties.Fragments; -import com.sun.tools.javac.resources.CompilerProperties.Notes; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @@ -2835,7 +2834,7 @@ public class Lower extends TreeTranslator { JCExpression exactnessCheck; JCExpression instanceOfExpr = translate(tree.expr); - if (types.isUnconditionallyExact(tree.expr.type, tree.pattern.type)) { + if (types.isUnconditionallyExactTypeBased(tree.expr.type, tree.pattern.type)) { // instanceOfExpr; true prefixStatement = make.Exec(instanceOfExpr); exactnessCheck = make.Literal(BOOLEAN, 1).setType(syms.booleanType.constType(1)); @@ -2844,7 +2843,7 @@ public class Lower extends TreeTranslator { prefixStatement = null; exactnessCheck = getExactnessCheck(tree, instanceOfExpr); } else if (tree.expr.type.isReference()) { - if (types.isUnconditionallyExact(types.unboxedType(tree.expr.type), tree.pattern.type)) { + if (types.isUnconditionallyExactTypeBased(types.unboxedType(tree.expr.type), tree.pattern.type)) { // instanceOfExpr != null prefixStatement = null; exactnessCheck = makeBinary(NE, instanceOfExpr, makeNull()); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java index 0cef9cc6602..5a1fe70dd9b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java @@ -37,7 +37,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; -import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -236,6 +236,7 @@ public class Modules extends JCTree.Visitor { setupAllModules(); //initialize the module graph Assert.checkNonNull(allModules); inInitModules = false; + return allModules; }, null); } finally { inInitModules = false; @@ -249,10 +250,11 @@ public class Modules extends JCTree.Visitor { //the next steps may query if the current module participates in preview, //and that requires a completed java.base: syms.java_base.complete(); + return modules; }, c); } - private boolean enter(List trees, Consumer> init, ClassSymbol c) { + private boolean enter(List trees, Function, Set> init, ClassSymbol c) { if (!allowModules) { for (JCCompilationUnit tree: trees) { tree.modle = syms.noModule; @@ -270,10 +272,13 @@ public class Modules extends JCTree.Visitor { setCompilationUnitModules(trees, roots, c); - init.accept(roots); + Set initialized = init.apply(roots); - for (ModuleSymbol msym: roots) { - msym.complete(); + for (ModuleSymbol msym : initialized) { + if (msym != syms.unnamedModule || + roots.contains(syms.unnamedModule)) { + msym.complete(); + } } } catch (CompletionFailure ex) { chk.completionError(null, ex); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index eea766f57c1..07f2a742bcb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -2810,7 +2810,12 @@ public class Resolve { Symbol resolveQualifiedMethod(DiagnosticPosition pos, Env env, Symbol location, Type site, Name name, List argtypes, List typeargtypes) { - return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes); + try { + return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes); + } catch (CompletionFailure cf) { + chk.completionError(pos, cf); + return methodNotFound.access(name, site.tsym); + } } private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext, DiagnosticPosition pos, Env env, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java index 58c36a5cf7c..11774c313e3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java @@ -921,7 +921,7 @@ public class TransPatterns extends TreeTranslator { JCBindingPattern binding = (JCBindingPattern) instanceofCheck.pattern; hasUnconditional = (!types.erasure(binding.type).isPrimitive() ? instanceofCheck.allowNull : - types.isUnconditionallyExact(commonNestedExpression.type, types.erasure(binding.type))) && + types.isUnconditionallyExactTypeBased(commonNestedExpression.type, types.erasure(binding.type))) && accList.tail.isEmpty(); List newLabel; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java index e5adecdb107..ae1aab1cefd 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java @@ -130,6 +130,7 @@ public class ClassFile { V68(68, 0), // JDK 24 V69(69, 0), // JDK 25 V70(70, 0), // JDK 26 + V71(71, 0), // JDK 27 ; // Reduce code churn when appending new constants Version(int major, int minor) { this.major = major; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java index 7899b8335b6..227143c3148 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java @@ -1854,14 +1854,17 @@ public class Code { } else { t1 = types.skipTypeVars(t1, false); t2 = types.skipTypeVars(t2, false); - List intersection = types.intersect( - t1.hasTag(ARRAY) ? - List.of(syms.serializableType, syms.cloneableType, syms.objectType) : - types.erasedSupertypes(t1), - t2.hasTag(ARRAY) ? - List.of(syms.serializableType, syms.cloneableType, syms.objectType) : - types.erasedSupertypes(t2)); - return intersection.head; + List result = types.closureMin( + types.intersect( + t1.hasTag(ARRAY) ? + List.of(syms.serializableType, syms.cloneableType, syms.objectType) : + types.erasedSupertypes(t1), + t2.hasTag(ARRAY) ? + List.of(syms.serializableType, syms.cloneableType, syms.objectType) : + types.erasedSupertypes(t2) + ) + ); + return result.head; } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java index f60adcb3b80..b0a298fc845 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java @@ -113,6 +113,9 @@ public enum Target { /** JDK 26. */ JDK1_26("26", 70, 0), + + /** JDK 27. */ + JDK1_27("27", 71, 0), ; // Reduce code churn when appending new constants private static final Context.Key targetKey = new Context.Key<>(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java index 4d679403ee7..af7d79d4195 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java @@ -226,6 +226,8 @@ public final class SourceLauncher { Object instance = null; + // Similar to sun.launcher.LauncherHelper#checkAndLoadMain, including + // checks performed in LauncherHelper#validateMainMethod if (!isStatic) { if (Modifier.isAbstract(mainClass.getModifiers())) { throw new Fault(Errors.CantInstantiate(mainClassName)); @@ -238,6 +240,10 @@ public final class SourceLauncher { throw new Fault(Errors.CantFindConstructor(mainClassName)); } + if (Modifier.isPrivate(constructor.getModifiers())) { + throw new Fault(Errors.CantUsePrivateConstructor(mainClassName)); + } + try { constructor.setAccessible(true); instance = constructor.newInstance(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java index c14767a7a8c..664ebc4c9c6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java @@ -33,6 +33,8 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.text.Collator; +import java.util.Collection; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; @@ -45,7 +47,6 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.StringJoiner; import java.util.TreeMap; -import java.util.TreeSet; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -323,12 +324,13 @@ public enum Option { @Override protected void help(Log log) { - StringJoiner sj = new StringJoiner(", "); + List releases = new ArrayList<>(); for(Source source : Source.values()) { if (source.isSupported()) - sj.add(source.name); + releases.add(source.name); } - super.help(log, log.localize(PrefixKind.JAVAC, descrKey, sj.toString())); + String formatted = formatAbbreviatedList(releases); + super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted)); } }, @@ -344,12 +346,13 @@ public enum Option { @Override protected void help(Log log) { - StringJoiner sj = new StringJoiner(", "); + List releases = new ArrayList<>(); for(Target target : Target.values()) { if (target.isSupported()) - sj.add(target.name); + releases.add(target.name); } - super.help(log, log.localize(PrefixKind.JAVAC, descrKey, sj.toString())); + String formatted = formatAbbreviatedList(releases); + super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted)); } }, @@ -364,15 +367,8 @@ public enum Option { false)) .collect(Collectors.toCollection(LinkedHashSet :: new)); - StringBuilder targets = new StringBuilder(); - String delim = ""; - for (String platform : platforms) { - targets.append(delim); - targets.append(platform); - delim = ", "; - } - - super.help(log, log.localize(PrefixKind.JAVAC, descrKey, targets.toString())); + String formatted = formatAbbreviatedList(platforms); + super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted)); } }, @@ -1369,6 +1365,41 @@ public enum Option { log.printRawLines(WriterKind.STDOUT, LARGE_INDENT + descr.replace("\n", "\n" + LARGE_INDENT)); } + /** + * Formats a collection of values as an abbreviated, comma separated list + * for use in javac help output. + * + * This helper assumes that the supported values form a dense sequence + * between the fourth and the (n - 3)rd entries. + * That matches the current policy for these values but is not + * guaranteed, and should be reconsidered if the structure of the values changes. + * + * @param values the values to format + * @return a comma separated representation of the values + */ + private static String formatAbbreviatedList(Collection values) { + List list = (values instanceof List) + ? (List) values + : new ArrayList<>(values); + + int size = list.size(); + if (size == 0) { + return ""; + } + if (size <= 6) { + return String.join(", ", list); + } + StringJoiner sj = new StringJoiner(", "); + for (int i = 0; i < 3; i++) { + sj.add(list.get(i)); + } + sj.add("..."); + for (int i = size - 3; i < size; i++) { + sj.add(list.get(i)); + } + return sj.toString(); + } + /** * Composes the initial synopsis of one of the forms for this option. * @param name the name of this form of the option diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java index 7aaf035fd36..bcc9ccd0113 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java @@ -55,7 +55,7 @@ import com.sun.tools.javac.util.StringUtils; * deletion without notice. */ @SupportedAnnotationTypes("*") -@SupportedSourceVersion(SourceVersion.RELEASE_26) +@SupportedSourceVersion(SourceVersion.RELEASE_27) public class PrintingProcessor extends AbstractProcessor { PrintWriter writer; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 6318476fca4..95a7546e2b3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -2464,6 +2464,11 @@ compiler.err.no.zipfs.for.archive=\ compiler.warn.div.zero=\ division by zero +# 0: type, 1: long, 2: number +# lint: lossy-conversions +compiler.warn.bit.shift.out.of.range=\ + shifting {0} by {1} bits is equivalent to shifting by {2} bit(s) + # lint: empty compiler.warn.empty.if=\ empty statement after if diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties index 6d4276c794b..7824772b1f3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties @@ -100,7 +100,8 @@ javac.opt.arg.Werror=\ (,)* javac.opt.Werror.custom=\ Specify lint categories for which warnings should terminate compilation,\n\ - separated by comma. Precede a key by ''-'' to exclude the specified category.\n\ + separated by comma.\n\ + Precede a key by ''-'' to exclude the specified category.\n\ Use --help-lint to see the supported keys. javac.opt.A=\ Options to pass to annotation processors @@ -228,7 +229,7 @@ javac.opt.Xlint.desc.incubating=\ Warn about use of incubating modules. javac.opt.Xlint.desc.lossy-conversions=\ - Warn about possible lossy conversions in compound assignment. + Warn about possible lossy conversions in compound assignment and bit shift operations. javac.opt.Xlint.desc.module=\ Warn about module system related issues. @@ -358,7 +359,8 @@ javac.opt.prefer=\ are found for an implicitly compiled class # L10N: do not localize: ''preview'' javac.opt.preview=\ - Enable preview language features. Also disables the ''preview'' lint category.\n\ + Enable preview language features.\n\ + Also disables the ''preview'' lint category.\n\ To be used in conjunction with either -source or --release. javac.opt.AT=\ Read options and filenames from file diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties index 122e5dca80d..36d50afad0f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties @@ -124,6 +124,12 @@ launcher.err.cant.access.main.method=\ launcher.err.cant.find.constructor=\ can''t find no argument constructor in class: {0} +# 0: string +launcher.err.cant.use.private.constructor=\ + no non-private zero argument constructor found in class {0}\n\ + remove private from existing constructor or define as:\n\ +\ public {0}() + # 0: string launcher.err.cant.access.constructor=\ can''t access no argument constructor in class: {0} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java index 0436f68b9e3..6501fd5d96c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -505,7 +505,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { // for default DiagnosticPosition public int getStartPosition() { - return TreeInfo.getStartPos(this); + return noNoPos(TreeInfo.getStartPos(this)); } // for default DiagnosticPosition @@ -515,7 +515,14 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { // for default DiagnosticPosition public int getEndPosition(EndPosTable endPosTable) { - return TreeInfo.getEndPos(this, endPosTable); + return noNoPos(TreeInfo.getEndPos(this, endPosTable)); + } + + private int noNoPos(int position) { + if (position == JCDiagnostic.NOPOS) { + return pos; + } + return position; } /** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java index af823024fab..3f73bfd2296 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -651,6 +651,11 @@ public class TreeInfo { if (tree == null) return Position.NOPOS; + if (endPosTable == null) { + // fall back on limited info in the tree + return endPos(tree); + } + int mapPos = endPosTable.getEndPos(tree); if (mapPos != Position.NOPOS) return mapPos; diff --git a/src/jdk.compiler/share/classes/module-info.java b/src/jdk.compiler/share/classes/module-info.java index 46ada3a12e7..4aa60a3dffe 100644 --- a/src/jdk.compiler/share/classes/module-info.java +++ b/src/jdk.compiler/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -165,7 +165,8 @@ import javax.tools.StandardLocation; * the next * {@code finally} {@code finally} clauses that do not terminate normally * {@code identity} use of a value-based class where an identity class is expected - * {@code lossy-conversions} possible lossy conversions in compound assignment + * {@code lossy-conversions} possible lossy conversions in compound assignments or bit shifts + * (more than \u00B131 bits for integers or \u00B163 bits for longs) * {@code missing-explicit-ctor} missing explicit constructors in public and protected classes * in exported packages * {@code module} module system related issues diff --git a/src/jdk.compiler/share/data/symbols/README b/src/jdk.compiler/share/data/symbols/README index 4c9f38f77b0..50f68bbe2f2 100644 --- a/src/jdk.compiler/share/data/symbols/README +++ b/src/jdk.compiler/share/data/symbols/README @@ -1,3 +1,3 @@ This directory contains history data for -release. -Please see $JDK_TOP_DIR/make/scripts/generate-symbol-data.sh for main usage. +Please see $JDK_TOP_DIR/bin/generate-symbol-data.sh for main usage. diff --git a/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt new file mode 100644 index 00000000000..fb1ec6ec7bb --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt @@ -0,0 +1,558 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name java.base +header exports java/io,java/lang,java/lang/annotation,java/lang/classfile,java/lang/classfile/attribute,java/lang/classfile/constantpool,java/lang/classfile/instruction,java/lang/constant,java/lang/foreign,java/lang/invoke,java/lang/module,java/lang/ref,java/lang/reflect,java/lang/runtime,java/math,java/net,java/net/spi,java/nio,java/nio/channels,java/nio/channels/spi,java/nio/charset,java/nio/charset/spi,java/nio/file,java/nio/file/attribute,java/nio/file/spi,java/security,java/security/cert,java/security/interfaces,java/security/spec,java/text,java/text/spi,java/time,java/time/chrono,java/time/format,java/time/temporal,java/time/zone,java/util,java/util/concurrent,java/util/concurrent/atomic,java/util/concurrent/locks,java/util/function,java/util/jar,java/util/random,java/util/regex,java/util/spi,java/util/stream,java/util/zip,javax/crypto,javax/crypto/interfaces,javax/crypto/spec,javax/net,javax/net/ssl,javax/security/auth,javax/security/auth/callback,javax/security/auth/login,javax/security/auth/spi,javax/security/auth/x500,javax/security/cert,jdk/internal/event[jdk.jfr],jdk/internal/javac[java.compiler\u005C;u002C;jdk.compiler],jdk/internal/vm/vector[jdk.incubator.vector] extraModulePackages jdk/internal/access/foreign,jdk/internal/classfile/impl,jdk/internal/constant,jdk/internal/foreign/abi,jdk/internal/foreign/abi/aarch64/linux,jdk/internal/foreign/abi/aarch64/macos,jdk/internal/foreign/abi/aarch64/windows,jdk/internal/foreign/abi/fallback,jdk/internal/foreign/abi/ppc64/aix,jdk/internal/foreign/abi/ppc64/linux,jdk/internal/foreign/abi/riscv64/linux,jdk/internal/foreign/abi/s390/linux,jdk/internal/foreign/abi/x64/sysv,jdk/internal/foreign/abi/x64/windows,jdk/internal/foreign/layout,jdk/internal/lang,sun/nio,sun/nio/ch,sun/net,jdk/internal/foreign,jdk/internal/foreign,sun/net,sun/nio/ch uses java/lang/System$LoggerFinder,java/net/ContentHandlerFactory,java/net/spi/InetAddressResolverProvider,java/net/spi/URLStreamHandlerProvider,java/nio/channels/spi/AsynchronousChannelProvider,java/nio/channels/spi/SelectorProvider,java/nio/charset/spi/CharsetProvider,java/nio/file/spi/FileSystemProvider,java/nio/file/spi/FileTypeDetector,java/security/Provider,java/text/spi/BreakIteratorProvider,java/text/spi/CollatorProvider,java/text/spi/DateFormatProvider,java/text/spi/DateFormatSymbolsProvider,java/text/spi/DecimalFormatSymbolsProvider,java/text/spi/NumberFormatProvider,java/time/chrono/AbstractChronology,java/time/chrono/Chronology,java/time/zone/ZoneRulesProvider,java/util/spi/CalendarDataProvider,java/util/spi/CalendarNameProvider,java/util/spi/CurrencyNameProvider,java/util/spi/LocaleNameProvider,java/util/spi/ResourceBundleControlProvider,java/util/spi/ResourceBundleProvider,java/util/spi/TimeZoneNameProvider,java/util/spi/ToolProvider,javax/security/auth/spi/LoginModule,jdk/internal/io/JdkConsoleProvider,jdk/internal/logger/DefaultLoggerFinder,sun/text/spi/JavaTimeDateTimePatternProvider,sun/util/locale/provider/LocaleDataMetaInfo,sun/util/resources/LocaleData$LocaleDataResourceBundleProvider,sun/util/spi/CalendarProvider provides interface\u0020;java/nio/file/spi/FileSystemProvider\u0020;impls\u0020;jdk/internal/jrtfs/JrtFileSystemProvider target macos-aarch64 flags 8000 + +class name java/lang/Character$UnicodeBlock +field name SIDETIC descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name SHARADA_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TOLONG_SIKI descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name BERIA_ERFE descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TANGUT_COMPONENTS_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name MISCELLANEOUS_SYMBOLS_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TAI_YO descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name CJK_UNIFIED_IDEOGRAPHS_EXTENSION_J descriptor Ljava/lang/Character$UnicodeBlock; flags 19 + +class name java/lang/Character$UnicodeScript +field name SIDETIC descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name TOLONG_SIKI descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name BERIA_ERFE descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name TAI_YO descriptor Ljava/lang/Character$UnicodeScript; flags 4019 + +class name java/lang/Class +header extends java/lang/Object implements java/io/Serializable,java/lang/reflect/GenericDeclaration,java/lang/reflect/Type,java/lang/reflect/AnnotatedElement,java/lang/invoke/TypeDescriptor$OfField,java/lang/constant/Constable flags 31 signature Ljava/lang/Object;Ljava/io/Serializable;Ljava/lang/reflect/GenericDeclaration;Ljava/lang/reflect/Type;Ljava/lang/reflect/AnnotatedElement;Ljava/lang/invoke/TypeDescriptor$OfField;>;Ljava/lang/constant/Constable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/TypeDescriptor$OfField outerClass java/lang/invoke/TypeDescriptor innerClassName OfField flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/ClassLoader +header extends java/lang/Object flags 421 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/LazyConstant +header extends java/lang/Object implements java/util/function/Supplier sealed true permittedSubclasses jdk/internal/lang/LazyConstantImpl flags 601 signature Ljava/lang/Object;Ljava/util/function/Supplier; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) +method name orElse descriptor (Ljava/lang/Object;)Ljava/lang/Object; flags 401 signature (TT;)TT; +method name get descriptor ()Ljava/lang/Object; flags 401 signature ()TT; +method name isInitialized descriptor ()Z flags 401 +method name equals descriptor (Ljava/lang/Object;)Z flags 401 +method name hashCode descriptor ()I flags 401 +method name toString descriptor ()Ljava/lang/String; flags 401 +method name of descriptor (Ljava/util/function/Supplier;)Ljava/lang/LazyConstant; flags 9 signature (Ljava/util/function/Supplier<+TT;>;)Ljava/lang/LazyConstant; + +class name java/lang/Math +-method name sinh descriptor (D)D +method name sinh descriptor (D)D flags 9 runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; + +class name java/lang/Object +header flags 21 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/Process +header extends java/lang/Object implements java/io/Closeable flags 421 +innerclass innerClass java/util/concurrent/ForkJoinPool$ManagedBlocker outerClass java/util/concurrent/ForkJoinPool innerClassName ManagedBlocker flags 609 +innerclass innerClass java/lang/ProcessHandle$Info outerClass java/lang/ProcessHandle innerClassName Info flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name close descriptor ()V thrownTypes java/io/IOException flags 1 + +-class name java/lang/StableValue + +class name java/lang/Thread +-method name stop descriptor ()V + +class name java/lang/classfile/ClassFile +field name JAVA_26_VERSION descriptor I constantValue 70 flags 19 + +class name java/lang/classfile/Signature$ClassTypeSig +-method name of descriptor (Ljava/lang/classfile/Signature$ClassTypeSig;Ljava/lang/constant/ClassDesc;[Ljava/lang/classfile/Signature$TypeArg;)Ljava/lang/classfile/Signature$ClassTypeSig; +method name of descriptor (Ljava/lang/classfile/Signature$ClassTypeSig;Ljava/lang/constant/ClassDesc;[Ljava/lang/classfile/Signature$TypeArg;)Ljava/lang/classfile/Signature$ClassTypeSig; flags 89 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +-class name java/lang/constant/AsTypeMethodHandleDesc + +class name java/lang/constant/ConstantDescs +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 + +class name java/lang/constant/DynamicConstantDesc +header extends java/lang/Object implements java/lang/constant/ConstantDesc flags 421 signature Ljava/lang/Object;Ljava/lang/constant/ConstantDesc; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/Enum$EnumDesc outerClass java/lang/Enum innerClassName EnumDesc flags 19 +innerclass innerClass java/lang/invoke/VarHandle$VarHandleDesc outerClass java/lang/invoke/VarHandle innerClassName VarHandleDesc flags 19 + +class name java/lang/constant/MethodHandleDesc +header extends java/lang/Object implements java/lang/constant/ConstantDesc sealed true permittedSubclasses jdk/internal/constant/AsTypeMethodHandleDesc,java/lang/constant/DirectMethodHandleDesc flags 601 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/BoundMethodHandle +header extends java/lang/invoke/MethodHandle flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/invoke/DelegatingMethodHandle +header extends java/lang/invoke/MethodHandle sealed true permittedSubclasses java/lang/invoke/MethodHandleImpl$AsVarargsCollector,java/lang/invoke/MethodHandleImpl$WrappedMember,java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle,java/lang/invoke/MethodHandleImpl$CountingWrapper flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 + +class name java/lang/invoke/DirectMethodHandle +header extends java/lang/invoke/MethodHandle nestMembers java/lang/invoke/DirectMethodHandle$StaticAccessor,java/lang/invoke/DirectMethodHandle$Accessor,java/lang/invoke/DirectMethodHandle$Constructor,java/lang/invoke/DirectMethodHandle$Interface,java/lang/invoke/DirectMethodHandle$Special sealed true permittedSubclasses java/lang/invoke/DirectMethodHandle$Special,java/lang/invoke/DirectMethodHandle$Interface,java/lang/invoke/DirectMethodHandle$Constructor,java/lang/invoke/DirectMethodHandle$Accessor,java/lang/invoke/DirectMethodHandle$StaticAccessor flags 20 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/DirectMethodHandle$Special outerClass java/lang/invoke/DirectMethodHandle innerClassName Special flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Interface outerClass java/lang/invoke/DirectMethodHandle innerClassName Interface flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$StaticAccessor outerClass java/lang/invoke/DirectMethodHandle innerClassName StaticAccessor flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Accessor outerClass java/lang/invoke/DirectMethodHandle innerClassName Accessor flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Constructor outerClass java/lang/invoke/DirectMethodHandle innerClassName Constructor flags 18 + +class name java/lang/invoke/DirectMethodHandle$Constructor +header extends java/lang/invoke/DirectMethodHandle nestHost java/lang/invoke/DirectMethodHandle flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/DirectMethodHandle$Constructor outerClass java/lang/invoke/DirectMethodHandle innerClassName Constructor flags 18 + +class name java/lang/invoke/LambdaForm +header extends java/lang/Object flags 20 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/invoke/LambdaMetafactory +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/MethodHandle +header extends java/lang/Object implements java/lang/constant/Constable sealed true permittedSubclasses java/lang/invoke/NativeMethodHandle,java/lang/invoke/DirectMethodHandle,java/lang/invoke/DelegatingMethodHandle,java/lang/invoke/BoundMethodHandle flags 421 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 + +class name java/lang/invoke/MethodHandleImpl +header extends java/lang/Object nestMembers java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle,java/lang/invoke/MethodHandleImpl$WrappedMember,java/lang/invoke/MethodHandleImpl$CountingWrapper,java/lang/invoke/MethodHandleImpl$AsVarargsCollector flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/MethodHandleImpl$AsVarargsCollector +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 + +class name java/lang/invoke/MethodHandleImpl$CountingWrapper +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 + +class name java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 + +class name java/lang/invoke/MethodHandleImpl$WrappedMember +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 + +class name java/lang/invoke/MethodHandles +header extends java/lang/Object nestMembers java/lang/invoke/MethodHandles$Lookup,java/lang/invoke/MethodHandles$Lookup$ClassOption flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/invoke/VarHandle$AccessMode outerClass java/lang/invoke/VarHandle innerClassName AccessMode flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup$ClassOption outerClass java/lang/invoke/MethodHandles$Lookup innerClassName ClassOption flags 4019 + +class name java/lang/invoke/StringConcatFactory +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/module/ModuleDescriptor +header extends java/lang/Object implements java/lang/Comparable nestMembers java/lang/module/ModuleDescriptor$Builder,java/lang/module/ModuleDescriptor$Version,java/lang/module/ModuleDescriptor$Provides,java/lang/module/ModuleDescriptor$Opens,java/lang/module/ModuleDescriptor$Opens$Modifier,java/lang/module/ModuleDescriptor$Exports,java/lang/module/ModuleDescriptor$Exports$Modifier,java/lang/module/ModuleDescriptor$Requires,java/lang/module/ModuleDescriptor$Requires$Modifier,java/lang/module/ModuleDescriptor$Modifier flags 31 signature Ljava/lang/Object;Ljava/lang/Comparable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/module/ModuleDescriptor$Version outerClass java/lang/module/ModuleDescriptor innerClassName Version flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Modifier outerClass java/lang/module/ModuleDescriptor innerClassName Modifier flags 4019 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Builder outerClass java/lang/module/ModuleDescriptor innerClassName Builder flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Provides outerClass java/lang/module/ModuleDescriptor innerClassName Provides flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Opens outerClass java/lang/module/ModuleDescriptor innerClassName Opens flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Exports outerClass java/lang/module/ModuleDescriptor innerClassName Exports flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Requires outerClass java/lang/module/ModuleDescriptor innerClassName Requires flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Opens$Modifier outerClass java/lang/module/ModuleDescriptor$Opens innerClassName Modifier flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Exports$Modifier outerClass java/lang/module/ModuleDescriptor$Exports innerClassName Modifier flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Requires$Modifier outerClass java/lang/module/ModuleDescriptor$Requires innerClassName Modifier flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/ref/PhantomReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/Reference +header extends java/lang/Object sealed true permittedSubclasses java/lang/ref/PhantomReference,java/lang/ref/SoftReference,java/lang/ref/WeakReference,java/lang/ref/FinalReference flags 421 signature Ljava/lang/Object; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} +-method name get descriptor ()Ljava/lang/Object; +method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; + +class name java/lang/ref/ReferenceQueue +header extends java/lang/Object flags 21 signature Ljava/lang/Object; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/SoftReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/WeakReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/reflect/ClassFileFormatVersion +field name RELEASE_26 descriptor Ljava/lang/reflect/ClassFileFormatVersion; flags 4019 + +class name java/lang/reflect/Field +header extends java/lang/reflect/AccessibleObject implements java/lang/reflect/Member flags 31 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/StackWalker$Option outerClass java/lang/StackWalker innerClassName Option flags 4019 +innerclass innerClass java/lang/StackWalker$StackFrame outerClass java/lang/StackWalker innerClassName StackFrame flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/runtime/ObjectMethods +header extends java/lang/Object flags 31 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/classfile/ClassFile$Option outerClass java/lang/classfile/ClassFile innerClassName Option flags 609 +innerclass innerClass java/lang/classfile/ClassFile$ClassHierarchyResolverOption outerClass java/lang/classfile/ClassFile innerClassName ClassHierarchyResolverOption flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup$ClassOption outerClass java/lang/invoke/MethodHandles$Lookup innerClassName ClassOption flags 4019 + +class name java/math/BigInteger +method name rootn descriptor (I)Ljava/math/BigInteger; flags 1 +method name rootnAndRemainder descriptor (I)[Ljava/math/BigInteger; flags 1 + +class name java/net/DatagramSocketImpl +-method name setTTL descriptor (B)V +-method name getTTL descriptor ()B + +class name java/net/MulticastSocket +-method name setTTL descriptor (B)V +-method name getTTL descriptor ()B +-method name send descriptor (Ljava/net/DatagramPacket;B)V + +class name java/net/ServerSocket +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/Socket +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/SocketImpl +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 4 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/SocketPermission +header extends java/security/Permission implements java/io/Serializable flags 31 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/net/URI +header extends java/lang/Object implements java/lang/Comparable,java/io/Serializable flags 31 signature Ljava/lang/Object;Ljava/lang/Comparable;Ljava/io/Serializable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/text/Normalizer$Form outerClass java/text/Normalizer innerClassName Form flags 4019 + +class name java/net/URL +header extends java/lang/Object implements java/io/Serializable flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/ScopedValue$Carrier outerClass java/lang/ScopedValue innerClassName Carrier flags 19 +innerclass innerClass java/lang/ScopedValue$CallableOp outerClass java/lang/ScopedValue innerClassName CallableOp flags 609 +innerclass innerClass java/io/ObjectInputStream$GetField outerClass java/io/ObjectInputStream innerClassName GetField flags 409 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/nio/ByteOrder +header extends java/lang/Enum flags 4031 signature Ljava/lang/Enum; +-field name BIG_ENDIAN descriptor Ljava/nio/ByteOrder; +-field name LITTLE_ENDIAN descriptor Ljava/nio/ByteOrder; +-method name toString descriptor ()Ljava/lang/String; +field name LITTLE_ENDIAN descriptor Ljava/nio/ByteOrder; flags 4019 +field name BIG_ENDIAN descriptor Ljava/nio/ByteOrder; flags 4019 +method name values descriptor ()[Ljava/nio/ByteOrder; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljava/nio/ByteOrder; flags 9 methodParameters 8000:null + +class name java/nio/DirectByteBuffer +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectCharBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectCharBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectDoubleBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectDoubleBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectFloatBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectFloatBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectIntBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectIntBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectLongBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectLongBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectShortBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectShortBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/charset/Charset +header extends java/lang/Object implements java/lang/Comparable flags 421 signature Ljava/lang/Object;Ljava/lang/Comparable; +innerclass innerClass java/lang/ScopedValue$Carrier outerClass java/lang/ScopedValue innerClassName Carrier flags 19 +innerclass innerClass java/lang/ScopedValue$CallableOp outerClass java/lang/ScopedValue innerClassName CallableOp flags 609 + +class name java/security/DEREncodable +header extends java/lang/Object sealed true permittedSubclasses java/security/AsymmetricKey,java/security/KeyPair,java/security/spec/PKCS8EncodedKeySpec,java/security/spec/X509EncodedKeySpec,javax/crypto/EncryptedPrivateKeyInfo,java/security/cert/X509Certificate,java/security/cert/X509CRL,java/security/PEM flags 601 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) + +class name java/security/PEM +header extends java/lang/Record implements java/security/DEREncodable record true flags 31 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +recordcomponent name type descriptor Ljava/lang/String; +recordcomponent name content descriptor Ljava/lang/String; +recordcomponent name leadingData descriptor [B +innerclass innerClass java/util/Base64$Decoder outerClass java/util/Base64 innerClassName Decoder flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name descriptor (Ljava/lang/String;Ljava/lang/String;[B)V flags 1 methodParameters 8000:type,8000:content,8000:leadingData +method name descriptor (Ljava/lang/String;Ljava/lang/String;)V flags 1 +method name toString descriptor ()Ljava/lang/String; flags 11 +method name decode descriptor ()[B flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name type descriptor ()Ljava/lang/String; flags 1 +method name content descriptor ()Ljava/lang/String; flags 1 +method name leadingData descriptor ()[B flags 1 + +class name java/security/PEMDecoder +header extends java/lang/Object flags 31 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +innerclass innerClass java/lang/ref/Cleaner$Cleanable outerClass java/lang/ref/Cleaner innerClassName Cleanable flags 609 +innerclass innerClass java/util/Base64$Decoder outerClass java/util/Base64 innerClassName Decoder flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +-class name java/security/PEMRecord + +class name java/security/SecureRandom +method name nextLong descriptor ()J flags 1 + +class name java/time/Duration +field name MIN descriptor Ljava/time/Duration; flags 19 +field name MAX descriptor Ljava/time/Duration; flags 19 + +class name java/time/Instant +method name plusSaturating descriptor (Ljava/time/Duration;)Ljava/time/Instant; flags 1 + +class name java/util/AbstractMap +header extends java/lang/Object implements java/util/Map nestMembers java/util/AbstractMap$SimpleImmutableEntry,java/util/AbstractMap$SimpleEntry flags 421 signature Ljava/lang/Object;Ljava/util/Map; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/util/AbstractMap$SimpleImmutableEntry outerClass java/util/AbstractMap innerClassName SimpleImmutableEntry flags 9 +innerclass innerClass java/util/AbstractMap$SimpleEntry outerClass java/util/AbstractMap innerClassName SimpleEntry flags 9 + +class name java/util/Collections +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/util/Comparator +method name max descriptor (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TU;TU;)TU; +method name min descriptor (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TU;TU;)TU; + +class name java/util/List +method name ofLazy descriptor (ILjava/util/function/IntFunction;)Ljava/util/List; flags 9 signature (ILjava/util/function/IntFunction<+TE;>;)Ljava/util/List; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) + +class name java/util/Locale +header extends java/lang/Object implements java/lang/Cloneable,java/io/Serializable nestMembers java/util/Locale$LanguageRange,java/util/Locale$FilteringMode,java/util/Locale$Builder,java/util/Locale$Category,java/util/Locale$IsoCountryCode flags 31 +innerclass innerClass java/util/Locale$Category outerClass java/util/Locale innerClassName Category flags 4019 +innerclass innerClass java/util/Locale$IsoCountryCode outerClass java/util/Locale innerClassName IsoCountryCode flags 4019 +innerclass innerClass java/io/ObjectOutputStream$PutField outerClass java/io/ObjectOutputStream innerClassName PutField flags 409 +innerclass innerClass java/io/ObjectInputStream$GetField outerClass java/io/ObjectInputStream innerClassName GetField flags 409 +innerclass innerClass java/util/Locale$FilteringMode outerClass java/util/Locale innerClassName FilteringMode flags 4019 +innerclass innerClass java/util/Locale$LanguageRange outerClass java/util/Locale innerClassName LanguageRange flags 19 +innerclass innerClass java/util/Locale$Builder outerClass java/util/Locale innerClassName Builder flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/util/Locale$IsoCountryCode +header extends java/lang/Enum nestHost java/util/Locale flags 4031 signature Ljava/lang/Enum; +innerclass innerClass java/util/Locale$IsoCountryCode outerClass java/util/Locale innerClassName IsoCountryCode flags 4019 + +class name java/util/Map +method name ofLazy descriptor (Ljava/util/Set;Ljava/util/function/Function;)Ljava/util/Map; flags 9 signature (Ljava/util/Set<+TK;>;Ljava/util/function/Function<-TK;+TV;>;)Ljava/util/Map; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) + +class name java/util/UUID +method name ofEpochMillis descriptor (J)Ljava/util/UUID; flags 9 + +class name java/util/WeakHashMap +header extends java/util/AbstractMap implements java/util/Map flags 21 signature Ljava/util/AbstractMap;Ljava/util/Map; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 + +class name java/util/concurrent/ConcurrentHashMap +header extends java/util/AbstractMap implements java/util/concurrent/ConcurrentMap,java/io/Serializable nestMembers java/util/concurrent/ConcurrentHashMap$EntrySetView,java/util/concurrent/ConcurrentHashMap$ValuesView,java/util/concurrent/ConcurrentHashMap$KeySetView,java/util/concurrent/ConcurrentHashMap$CollectionView flags 21 signature Ljava/util/AbstractMap;Ljava/util/concurrent/ConcurrentMap;Ljava/io/Serializable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$KeySetView outerClass java/util/concurrent/ConcurrentHashMap innerClassName KeySetView flags 19 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$ValuesView outerClass java/util/concurrent/ConcurrentHashMap innerClassName ValuesView flags 18 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$EntrySetView outerClass java/util/concurrent/ConcurrentHashMap innerClassName EntrySetView flags 18 +innerclass innerClass java/io/ObjectOutputStream$PutField outerClass java/io/ObjectOutputStream innerClassName PutField flags 409 +innerclass innerClass java/util/AbstractMap$SimpleImmutableEntry outerClass java/util/AbstractMap innerClassName SimpleImmutableEntry flags 9 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$CollectionView outerClass java/util/concurrent/ConcurrentHashMap innerClassName CollectionView flags 408 + +class name java/util/concurrent/StructuredTaskScope +-method name open descriptor (Ljava/util/concurrent/StructuredTaskScope$Joiner;Ljava/util/function/Function;)Ljava/util/concurrent/StructuredTaskScope; +method name open descriptor (Ljava/util/concurrent/StructuredTaskScope$Joiner;Ljava/util/function/UnaryOperator;)Ljava/util/concurrent/StructuredTaskScope; flags 9 signature (Ljava/util/concurrent/StructuredTaskScope$Joiner<-TT;+TR;>;Ljava/util/function/UnaryOperator;)Ljava/util/concurrent/StructuredTaskScope; + +class name java/util/concurrent/StructuredTaskScope$Joiner +header extends java/lang/Object nestHost java/util/concurrent/StructuredTaskScope flags 601 signature Ljava/lang/Object; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;STRUCTURED_CONCURRENCY;) +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$TimeoutException outerClass java/util/concurrent/StructuredTaskScope innerClassName TimeoutException flags 19 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Joiner outerClass java/util/concurrent/StructuredTaskScope innerClassName Joiner flags 609 +-method name onFork descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +-method name onComplete descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +-method name allSuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +-method name anySuccessfulResultOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +-method name allUntil descriptor (Ljava/util/function/Predicate;)Ljava/util/concurrent/StructuredTaskScope$Joiner; +method name onFork descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z flags 1 signature (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +method name onComplete descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z flags 1 signature (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +method name onTimeout descriptor ()V flags 1 +method name allSuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature ()Ljava/util/concurrent/StructuredTaskScope$Joiner;>; +method name anySuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +method name allUntil descriptor (Ljava/util/function/Predicate;)Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature (Ljava/util/function/Predicate;>;)Ljava/util/concurrent/StructuredTaskScope$Joiner;>;>; + +class name java/util/concurrent/StructuredTaskScopeImpl +header extends java/lang/Object implements java/util/concurrent/StructuredTaskScope nestMembers java/util/concurrent/StructuredTaskScopeImpl$ConfigImpl,java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl flags 30 signature Ljava/lang/Object;Ljava/util/concurrent/StructuredTaskScope; +innerclass innerClass java/util/concurrent/StructuredTaskScope$Joiner outerClass java/util/concurrent/StructuredTaskScope innerClassName Joiner flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$ConfigImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName ConfigImpl flags 18 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Configuration outerClass java/util/concurrent/StructuredTaskScope innerClassName Configuration flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName SubtaskImpl flags 18 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$FailedException outerClass java/util/concurrent/StructuredTaskScope innerClassName FailedException flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl +header extends java/lang/Object implements java/util/concurrent/StructuredTaskScope$Subtask,java/lang/Runnable nestHost java/util/concurrent/StructuredTaskScopeImpl flags 30 signature Ljava/lang/Object;Ljava/util/concurrent/StructuredTaskScope$Subtask;Ljava/lang/Runnable; +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName SubtaskImpl flags 18 +innerclass innerClass java/lang/Thread$State outerClass java/lang/Thread innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 + +class name java/util/stream/Collectors +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/stream/Collector$Characteristics outerClass java/util/stream/Collector innerClassName Characteristics flags 4019 +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name javax/crypto/EncryptedPrivateKeyInfo +header extends java/lang/Object implements java/security/DEREncodable flags 21 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +-method name encryptKey descriptor (Ljava/security/PrivateKey;[CLjava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name encryptKey descriptor (Ljava/security/PrivateKey;[C)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name encryptKey descriptor (Ljava/security/PrivateKey;Ljava/security/Key;Ljava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;Ljava/security/SecureRandom;)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name getKey descriptor ([C)Ljava/security/PrivateKey; +-method name getKey descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/PrivateKey; +method name encrypt descriptor (Ljava/security/DEREncodable;[CLjava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name encrypt descriptor (Ljava/security/DEREncodable;[C)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name encrypt descriptor (Ljava/security/DEREncodable;Ljava/security/Key;Ljava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;Ljava/security/SecureRandom;)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKey descriptor ([C)Ljava/security/PrivateKey; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKey descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/PrivateKey; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKeyPair descriptor ([C)Ljava/security/KeyPair; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKeyPair descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/KeyPair; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) + +class name jdk/internal/classfile/impl/DirectCodeBuilder +header extends jdk/internal/classfile/impl/AbstractDirectBuilder implements jdk/internal/classfile/impl/TerminalCodeBuilder flags 31 signature Ljdk/internal/classfile/impl/AbstractDirectBuilder;Ljdk/internal/classfile/impl/TerminalCodeBuilder; +innerclass innerClass jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl outerClass jdk/internal/classfile/impl/AbstractPseudoInstruction innerClassName ExceptionCatchImpl flags 19 +innerclass innerClass java/lang/classfile/Opcode$Kind outerClass java/lang/classfile/Opcode innerClassName Kind flags 4019 + +class name jdk/internal/classfile/impl/SignaturesImpl +method name nextIdentifierEnd descriptor (Ljava/lang/String;I)I flags 9 +method name validateIdentifier descriptor (Ljava/lang/String;)Ljava/lang/String; flags 9 +method name validatePackageSpecifierPlusIdentifier descriptor (Ljava/lang/String;)Ljava/lang/String; flags 9 +method name validateNonVoid descriptor (Ljava/lang/classfile/Signature;)Ljava/lang/classfile/Signature; flags 9 +method name validateArgumentList descriptor ([Ljava/lang/classfile/Signature;)Ljava/util/List; flags 9 signature ([Ljava/lang/classfile/Signature;)Ljava/util/List; +method name validateArgumentList descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;)Ljava/util/List; + +class name jdk/internal/classfile/impl/Util +header extends java/lang/Object nestMembers jdk/internal/classfile/impl/Util$WritableLocalVariable,jdk/internal/classfile/impl/Util$Writable flags 31 +innerclass innerClass java/lang/classfile/AttributeMapper$AttributeStability outerClass java/lang/classfile/AttributeMapper innerClassName AttributeStability flags 4019 +innerclass innerClass java/lang/classfile/ClassFile$AttributesProcessingOption outerClass java/lang/classfile/ClassFile innerClassName AttributesProcessingOption flags 4019 +innerclass innerClass java/lang/classfile/Opcode$Kind outerClass java/lang/classfile/Opcode innerClassName Kind flags 4019 +innerclass innerClass jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl outerClass jdk/internal/classfile/impl/AbstractPoolEntry innerClassName Utf8EntryImpl flags 19 +innerclass innerClass jdk/internal/classfile/impl/Util$Writable outerClass jdk/internal/classfile/impl/Util innerClassName Writable flags 608 +innerclass innerClass jdk/internal/classfile/impl/Util$WritableLocalVariable outerClass jdk/internal/classfile/impl/Util innerClassName WritableLocalVariable flags 608 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name sanitizeU1List descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;)Ljava/util/List; +method name sanitizeU2List descriptor (Ljava/util/Collection;)Ljava/util/List; flags 9 signature (Ljava/util/Collection;)Ljava/util/List; +method name sanitizeParameterAnnotations descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;>;)Ljava/util/List;>; +method name checkU1 descriptor (ILjava/lang/String;)I flags 9 +method name checkU2 descriptor (ILjava/lang/String;)C flags 9 +method name outOfRangeException descriptor (ILjava/lang/String;Ljava/lang/String;)Ljava/lang/IllegalArgumentException; flags 9 +method name checkFlags descriptor (I)C flags 9 + +class name jdk/internal/constant/AsTypeMethodHandleDesc +header extends java/lang/constant/DynamicConstantDesc implements java/lang/constant/MethodHandleDesc flags 31 signature Ljava/lang/constant/DynamicConstantDesc;Ljava/lang/constant/MethodHandleDesc; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 +method name descriptor (Ljava/lang/constant/MethodHandleDesc;Ljava/lang/constant/MethodTypeDesc;)V flags 1 +method name invocationType descriptor ()Ljava/lang/constant/MethodTypeDesc; flags 1 +method name resolveConstantDesc descriptor (Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/invoke/MethodHandle; thrownTypes java/lang/ReflectiveOperationException flags 1 +method name toString descriptor ()Ljava/lang/String; flags 1 +method name resolveConstantDesc descriptor (Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/Object; thrownTypes java/lang/ReflectiveOperationException flags 1041 methodParameters 1000:null + +class name jdk/internal/constant/PrimitiveClassDescImpl +header extends java/lang/constant/DynamicConstantDesc implements java/lang/constant/ClassDesc flags 31 signature Ljava/lang/constant/DynamicConstantDesc;>;Ljava/lang/constant/ClassDesc; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/invoke/TypeDescriptor$OfField outerClass java/lang/invoke/TypeDescriptor innerClassName OfField flags 609 + +class name jdk/internal/lang/LazyConstantImpl +header extends java/lang/Object implements java/lang/LazyConstant flags 31 signature Ljava/lang/Object;Ljava/lang/LazyConstant; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name orElse descriptor (Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TT;)TT; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name isInitialized descriptor ()Z flags 1 runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name toString descriptor ()Ljava/lang/String; flags 1 +method name ofLazy descriptor (Ljava/util/function/Supplier;)Ljdk/internal/lang/LazyConstantImpl; flags 9 signature (Ljava/util/function/Supplier<+TT;>;)Ljdk/internal/lang/LazyConstantImpl; + +-class name jdk/internal/lang/stable/StableValueImpl + +class name jdk/internal/vm/vector/VectorSupport +-method name loadWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)Ljdk/internal/vm/vector/VectorSupport$Vector; +-method name storeWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V +method name loadWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)Ljdk/internal/vm/vector/VectorSupport$Vector; flags 9 signature ;W:Ljdk/internal/vm/vector/VectorSupport$Vector;S:Ljdk/internal/vm/vector/VectorSupport$VectorSpecies;M:Ljdk/internal/vm/vector/VectorSupport$VectorMask;E:Ljava/lang/Object;>(Ljava/lang/Class<+TV;>;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class<+Ljdk/internal/vm/vector/VectorSupport$Vector;>;ILjava/lang/Object;JTW;TW;TW;TW;TM;TC;I[IITS;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)TV; runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; +method name storeWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V flags 9 signature ;W:Ljdk/internal/vm/vector/VectorSupport$Vector;M:Ljdk/internal/vm/vector/VectorSupport$VectorMask;E:Ljava/lang/Object;>(Ljava/lang/Class<+TV;>;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class<+Ljdk/internal/vm/vector/VectorSupport$Vector;>;ILjava/lang/Object;JTW;TV;TM;TC;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; + +class name sun/nio/Cleaner +header extends java/lang/Object flags 601 +method name clean descriptor ()V flags 401 + +class name sun/nio/ch/DirectBuffer +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 401 + diff --git a/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt new file mode 100644 index 00000000000..cb6ad893ace --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt @@ -0,0 +1,85 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name javax/lang/model/SourceVersion +field name RELEASE_26 descriptor Ljavax/lang/model/SourceVersion; flags 4019 + +class name javax/lang/model/util/AbstractAnnotationValueVisitor14 +header extends javax/lang/model/util/AbstractAnnotationValueVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractAnnotationValueVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractAnnotationValueVisitorPreview +header extends javax/lang/model/util/AbstractAnnotationValueVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractAnnotationValueVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractElementVisitor14 +header extends javax/lang/model/util/AbstractElementVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractElementVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractElementVisitorPreview +header extends javax/lang/model/util/AbstractElementVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractElementVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractTypeVisitor14 +header extends javax/lang/model/util/AbstractTypeVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractTypeVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractTypeVisitorPreview +header extends javax/lang/model/util/AbstractTypeVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractTypeVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementKindVisitor14 +header extends javax/lang/model/util/ElementKindVisitor9 flags 21 signature Ljavax/lang/model/util/ElementKindVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementKindVisitorPreview +header extends javax/lang/model/util/ElementKindVisitor14 flags 21 signature Ljavax/lang/model/util/ElementKindVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementScanner14 +header extends javax/lang/model/util/ElementScanner9 flags 21 signature Ljavax/lang/model/util/ElementScanner9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementScannerPreview +header extends javax/lang/model/util/ElementScanner14 flags 21 signature Ljavax/lang/model/util/ElementScanner14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleAnnotationValueVisitor14 +header extends javax/lang/model/util/SimpleAnnotationValueVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleAnnotationValueVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleAnnotationValueVisitorPreview +header extends javax/lang/model/util/SimpleAnnotationValueVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleAnnotationValueVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleElementVisitor14 +header extends javax/lang/model/util/SimpleElementVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleElementVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleElementVisitorPreview +header extends javax/lang/model/util/SimpleElementVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleElementVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleTypeVisitor14 +header extends javax/lang/model/util/SimpleTypeVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleTypeVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleTypeVisitorPreview +header extends javax/lang/model/util/SimpleTypeVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleTypeVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/TypeKindVisitor14 +header extends javax/lang/model/util/TypeKindVisitor9 flags 21 signature Ljavax/lang/model/util/TypeKindVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/TypeKindVisitorPreview +header extends javax/lang/model/util/TypeKindVisitor14 flags 21 signature Ljavax/lang/model/util/TypeKindVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + diff --git a/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt new file mode 100644 index 00000000000..f75ff5b3fac --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt @@ -0,0 +1,90 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name java.desktop +header exports java/awt,java/awt/color,java/awt/desktop,java/awt/dnd,java/awt/event,java/awt/font,java/awt/geom,java/awt/im,java/awt/im/spi,java/awt/image,java/awt/image/renderable,java/awt/print,java/beans,java/beans/beancontext,javax/accessibility,javax/imageio,javax/imageio/event,javax/imageio/metadata,javax/imageio/plugins/bmp,javax/imageio/plugins/jpeg,javax/imageio/plugins/tiff,javax/imageio/spi,javax/imageio/stream,javax/print,javax/print/attribute,javax/print/attribute/standard,javax/print/event,javax/sound,javax/sound/midi,javax/sound/midi/spi,javax/sound/sampled,javax/sound/sampled/spi,javax/swing,javax/swing/border,javax/swing/colorchooser,javax/swing/event,javax/swing/filechooser,javax/swing/plaf,javax/swing/plaf/basic,javax/swing/plaf/metal,javax/swing/plaf/multi,javax/swing/plaf/nimbus,javax/swing/plaf/synth,javax/swing/table,javax/swing/text,javax/swing/text/html,javax/swing/text/html/parser,javax/swing/text/rtf,javax/swing/tree,javax/swing/undo extraModulePackages sun/print requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.prefs\u0020;flags\u0020;0,name\u0020;java.datatransfer\u0020;flags\u0020;20,name\u0020;java.xml\u0020;flags\u0020;20 uses java/awt/im/spi/InputMethodDescriptor,javax/accessibility/AccessibilityProvider,javax/imageio/spi/ImageInputStreamSpi,javax/imageio/spi/ImageOutputStreamSpi,javax/imageio/spi/ImageReaderSpi,javax/imageio/spi/ImageTranscoderSpi,javax/imageio/spi/ImageWriterSpi,javax/print/PrintServiceLookup,javax/print/StreamPrintServiceFactory,javax/sound/midi/spi/MidiDeviceProvider,javax/sound/midi/spi/MidiFileReader,javax/sound/midi/spi/MidiFileWriter,javax/sound/midi/spi/SoundbankReader,javax/sound/sampled/spi/AudioFileReader,javax/sound/sampled/spi/AudioFileWriter,javax/sound/sampled/spi/FormatConversionProvider,javax/sound/sampled/spi/MixerProvider,sun/swing/InteropProvider provides interface\u0020;sun/datatransfer/DesktopDatatransferService\u0020;impls\u0020;sun/awt/datatransfer/DesktopDatatransferServiceImpl,interface\u0020;java/net/ContentHandlerFactory\u0020;impls\u0020;sun/awt/www/content/MultimediaContentHandlers,interface\u0020;javax/print/PrintServiceLookup\u0020;impls\u0020;sun/print/PrintServiceLookupProvider,interface\u0020;javax/print/StreamPrintServiceFactory\u0020;impls\u0020;sun/print/PSStreamPrinterFactory,interface\u0020;javax/sound/midi/spi/MidiDeviceProvider\u0020;impls\u0020;com/sun/media/sound/MidiInDeviceProvider\u005C;u002C;com/sun/media/sound/MidiOutDeviceProvider\u005C;u002C;com/sun/media/sound/RealTimeSequencerProvider\u005C;u002C;com/sun/media/sound/SoftProvider,interface\u0020;javax/sound/midi/spi/MidiFileReader\u0020;impls\u0020;com/sun/media/sound/StandardMidiFileReader,interface\u0020;javax/sound/midi/spi/MidiFileWriter\u0020;impls\u0020;com/sun/media/sound/StandardMidiFileWriter,interface\u0020;javax/sound/midi/spi/SoundbankReader\u0020;impls\u0020;com/sun/media/sound/AudioFileSoundbankReader\u005C;u002C;com/sun/media/sound/DLSSoundbankReader\u005C;u002C;com/sun/media/sound/JARSoundbankReader\u005C;u002C;com/sun/media/sound/SF2SoundbankReader,interface\u0020;javax/sound/sampled/spi/AudioFileReader\u0020;impls\u0020;com/sun/media/sound/AiffFileReader\u005C;u002C;com/sun/media/sound/AuFileReader\u005C;u002C;com/sun/media/sound/SoftMidiAudioFileReader\u005C;u002C;com/sun/media/sound/WaveFileReader\u005C;u002C;com/sun/media/sound/WaveFloatFileReader\u005C;u002C;com/sun/media/sound/WaveExtensibleFileReader,interface\u0020;javax/sound/sampled/spi/AudioFileWriter\u0020;impls\u0020;com/sun/media/sound/AiffFileWriter\u005C;u002C;com/sun/media/sound/AuFileWriter\u005C;u002C;com/sun/media/sound/WaveFileWriter\u005C;u002C;com/sun/media/sound/WaveFloatFileWriter,interface\u0020;javax/sound/sampled/spi/FormatConversionProvider\u0020;impls\u0020;com/sun/media/sound/AlawCodec\u005C;u002C;com/sun/media/sound/AudioFloatFormatConverter\u005C;u002C;com/sun/media/sound/PCMtoPCMCodec\u005C;u002C;com/sun/media/sound/UlawCodec,interface\u0020;javax/sound/sampled/spi/MixerProvider\u0020;impls\u0020;com/sun/media/sound/DirectAudioDeviceProvider\u005C;u002C;com/sun/media/sound/PortMixerProvider target macos-aarch64 flags 8000 + +-class name java/applet/Applet + +-class name java/applet/Applet$AccessibleApplet + +-class name java/applet/AppletContext + +-class name java/applet/AppletStub + +-class name java/applet/AudioClip + +class name java/awt/Robot +field name DEFAULT_DELAY descriptor I constantValue 20 flags 19 +field name DEFAULT_STEP_LENGTH descriptor I constantValue 2 flags 19 +method name click descriptor (I)V flags 1 +method name click descriptor ()V flags 1 +method name waitForIdle descriptor (I)V flags 1 +method name glide descriptor (II)V flags 1 +method name glide descriptor (IIII)V flags 1 +method name glide descriptor (IIIIII)V flags 1 +method name type descriptor (I)V flags 21 +method name type descriptor (C)V flags 21 + +-class name java/beans/AppletInitializer + +class name java/beans/Beans +-method name instantiate descriptor (Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/beans/beancontext/BeanContext;Ljava/beans/AppletInitializer;)Ljava/lang/Object; + +class name javax/imageio/spi/ServiceRegistry +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileCacheImageInputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileImageInputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileImageOutputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/ImageInputStreamImpl +-method name finalize descriptor ()V + +class name javax/imageio/stream/MemoryCacheImageInputStream +-method name finalize descriptor ()V + +-class name javax/swing/JApplet + +-class name javax/swing/JApplet$AccessibleJApplet + +class name javax/swing/JTable +-method name setShowGrid descriptor (Z)V +method name setShowGrid descriptor (Z)V flags 1 runtimeAnnotations @Ljava/beans/BeanProperty;(description="Whether\u005C;u0020;grid\u005C;u0020;lines\u005C;u0020;are\u005C;u0020;drawn\u005C;u0020;around\u005C;u0020;the\u005C;u0020;cells.") + +class name javax/swing/RepaintManager +-method name addDirtyRegion descriptor (Ljava/applet/Applet;IIII)V + +class name javax/swing/plaf/synth/SynthPasswordFieldUI +-method name installKeyboardActions descriptor ()V + diff --git a/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt new file mode 100644 index 00000000000..03dacce810b --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt @@ -0,0 +1,37 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name java/lang/management/MemoryMXBean +method name getTotalGcCpuTime descriptor ()J flags 1 + +class name javax/management/modelmbean/DescriptorSupport +-method name descriptor (Ljava/lang/String;)V +-method name toXMLString descriptor ()Ljava/lang/String; + +-class name javax/management/modelmbean/XMLParseException + diff --git a/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt new file mode 100644 index 00000000000..bddf5c8d137 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt @@ -0,0 +1,125 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name java/net/http/HttpClient$Version +field name HTTP_3 descriptor Ljava/net/http/HttpClient$Version; flags 4019 + +class name java/net/http/HttpOption +header extends java/lang/Object nestMembers java/net/http/HttpOption$Http3DiscoveryMode sealed true permittedSubclasses java/net/http/HttpRequestOptionImpl flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +field name H3_DISCOVERY descriptor Ljava/net/http/HttpOption; flags 19 signature Ljava/net/http/HttpOption; +method name name descriptor ()Ljava/lang/String; flags 401 +method name type descriptor ()Ljava/lang/Class; flags 401 signature ()Ljava/lang/Class; + +class name java/net/http/HttpOption$Http3DiscoveryMode +header extends java/lang/Enum nestHost java/net/http/HttpOption flags 4031 signature Ljava/lang/Enum; +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +field name ANY descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +field name ALT_SVC descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +field name HTTP_3_URI_ONLY descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +method name values descriptor ()[Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 9 methodParameters 8000:null + +class name java/net/http/HttpRequest +header extends java/lang/Object nestMembers java/net/http/HttpRequest$BodyPublishers,java/net/http/HttpRequest$BodyPublisher,java/net/http/HttpRequest$Builder flags 421 +innerclass innerClass java/net/http/HttpRequest$Builder outerClass java/net/http/HttpRequest innerClassName Builder flags 609 +innerclass innerClass java/net/http/HttpRequest$BodyPublishers outerClass java/net/http/HttpRequest innerClassName BodyPublishers flags 9 +innerclass innerClass java/net/http/HttpRequest$BodyPublisher outerClass java/net/http/HttpRequest innerClassName BodyPublisher flags 609 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name getOption descriptor (Ljava/net/http/HttpOption;)Ljava/util/Optional; flags 1 signature (Ljava/net/http/HttpOption;)Ljava/util/Optional; + +class name java/net/http/HttpRequest$BodyPublishers +method name ofFileChannel descriptor (Ljava/nio/channels/FileChannel;JJ)Ljava/net/http/HttpRequest$BodyPublisher; thrownTypes java/io/IOException flags 9 + +class name java/net/http/HttpRequest$Builder +method name setOption descriptor (Ljava/net/http/HttpOption;Ljava/lang/Object;)Ljava/net/http/HttpRequest$Builder; flags 1 signature (Ljava/net/http/HttpOption;TT;)Ljava/net/http/HttpRequest$Builder; + +class name java/net/http/HttpRequestOptionImpl +header extends java/lang/Record implements java/net/http/HttpOption record true flags 30 signature Ljava/lang/Record;Ljava/net/http/HttpOption; +recordcomponent name type descriptor Ljava/lang/Class; signature Ljava/lang/Class; +recordcomponent name name descriptor Ljava/lang/String; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name toString descriptor ()Ljava/lang/String; flags 1 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name type descriptor ()Ljava/lang/Class; flags 1 signature ()Ljava/lang/Class; +method name name descriptor ()Ljava/lang/String; flags 1 + +class name java/net/http/HttpResponse +header extends java/lang/Object nestMembers java/net/http/HttpResponse$BodySubscribers,java/net/http/HttpResponse$BodySubscriber,java/net/http/HttpResponse$PushPromiseHandler,java/net/http/HttpResponse$PushPromiseHandler$PushId,java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId,java/net/http/HttpResponse$BodyHandlers,java/net/http/HttpResponse$BodyHandler,java/net/http/HttpResponse$ResponseInfo flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpResponse$BodySubscribers outerClass java/net/http/HttpResponse innerClassName BodySubscribers flags 9 +innerclass innerClass java/net/http/HttpResponse$BodySubscriber outerClass java/net/http/HttpResponse innerClassName BodySubscriber flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$BodyHandlers outerClass java/net/http/HttpResponse innerClassName BodyHandlers flags 9 +innerclass innerClass java/net/http/HttpResponse$BodyHandler outerClass java/net/http/HttpResponse innerClassName BodyHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$ResponseInfo outerClass java/net/http/HttpResponse innerClassName ResponseInfo flags 609 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 + +class name java/net/http/HttpResponse$PushPromiseHandler +header extends java/lang/Object nestHost java/net/http/HttpResponse flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$BodyHandler outerClass java/net/http/HttpResponse innerClassName BodyHandler flags 609 +method name applyPushPromise descriptor (Ljava/net/http/HttpRequest;Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;Ljava/util/function/Function;)V flags 1 signature (Ljava/net/http/HttpRequest;Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;Ljava/util/function/Function;Ljava/util/concurrent/CompletableFuture;>;>;)V +method name notifyAdditionalPromise descriptor (Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;)V flags 1 + +class name java/net/http/HttpResponse$PushPromiseHandler$PushId +header extends java/lang/Object nestHost java/net/http/HttpResponse sealed true permittedSubclasses java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId flags 601 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 + +class name java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId +header extends java/lang/Record implements java/net/http/HttpResponse$PushPromiseHandler$PushId nestHost java/net/http/HttpResponse record true flags 31 +recordcomponent name pushId descriptor J +recordcomponent name connectionLabel descriptor Ljava/lang/String; +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name descriptor (JLjava/lang/String;)V flags 1 methodParameters 0:pushId,0:connectionLabel +method name toString descriptor ()Ljava/lang/String; flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name pushId descriptor ()J flags 1 +method name connectionLabel descriptor ()Ljava/lang/String; flags 1 + +class name java/net/http/StreamLimitException +header extends java/io/IOException flags 31 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +method name descriptor (Ljava/net/http/HttpClient$Version;Ljava/lang/String;)V flags 1 +method name version descriptor ()Ljava/net/http/HttpClient$Version; flags 11 + +class name java/net/http/UnsupportedProtocolVersionException +header extends java/io/IOException flags 31 +method name descriptor (Ljava/lang/String;)V flags 1 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt new file mode 100644 index 00000000000..70cc330edca --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt @@ -0,0 +1,32 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name com/sun/net/httpserver/HttpExchange +field name RSPBODY_EMPTY descriptor J constantValue -1 flags 19 +field name RSPBODY_CHUNKED descriptor J constantValue 0 flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt new file mode 100644 index 00000000000..223be24ab56 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt @@ -0,0 +1,32 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name jdk/incubator/vector/VectorOperators +-field name SUADD descriptor Ljdk/incubator/vector/VectorOperators$Binary; +field name SUADD descriptor Ljdk/incubator/vector/VectorOperators$Associative; flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt new file mode 100644 index 00000000000..47838de0844 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jartool +header exports jdk/security/jarsigner requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;jdk.internal.opt\u0020;flags\u0020;0 provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;sun/tools/jar/JarToolProvider target macos-aarch64 moduleMainClass sun/tools/jar/Main flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt new file mode 100644 index 00000000000..e5d0bb627e5 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jdeps +header requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.compiler\u0020;flags\u0020;0,name\u0020;jdk.compiler\u0020;flags\u0020;0,name\u0020;jdk.internal.opt\u0020;flags\u0020;0 uses com/sun/tools/javac/platform/PlatformProvider provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;com/sun/tools/javap/Main$JavapToolProvider\u005C;u002C;com/sun/tools/jdeps/Main$JDepsToolProvider\u005C;u002C;com/sun/tools/jnativescan/Main$Provider target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt new file mode 100644 index 00000000000..2e3c13ea64c --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jfr +header exports jdk/jfr,jdk/jfr/consumer requires name\u0020;java.base\u0020;flags\u0020;8000 target macos-aarch64 moduleMainClass jdk/jfr/internal/tool/Main flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt new file mode 100644 index 00000000000..e3e9eadf355 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jlink +header requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;jdk.internal.opt\u0020;flags\u0020;0,name\u0020;jdk.jdeps\u0020;flags\u0020;0 uses jdk/tools/jlink/plugin/Plugin provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;jdk/tools/jmod/Main$JmodToolProvider\u005C;u002C;jdk/tools/jlink/internal/Main$JlinkToolProvider,interface\u0020;jdk/tools/jlink/plugin/Plugin\u0020;impls\u0020;jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludePlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeFilesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeJmodSectionPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/LegalNoticeFilePlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/SystemModulesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/StripNativeCommandsPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/OrderResourcesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/DefaultCompressPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeVMPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/AddOptionsPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorBugURLPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorVMBugURLPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorVersionPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/CDSPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/SaveJlinkArgfilesPlugin target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt new file mode 100644 index 00000000000..1dff60fc776 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt @@ -0,0 +1,169 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jshell +header exports jdk/jshell,jdk/jshell/execution,jdk/jshell/spi,jdk/jshell/tool requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.logging\u0020;flags\u0020;0,name\u0020;jdk.compiler\u0020;flags\u0020;0,name\u0020;jdk.internal.ed\u0020;flags\u0020;0,name\u0020;jdk.internal.le\u0020;flags\u0020;0,name\u0020;jdk.internal.md\u0020;flags\u0020;0,name\u0020;jdk.internal.opt\u0020;flags\u0020;0,name\u0020;java.compiler\u0020;flags\u0020;20,name\u0020;java.prefs\u0020;flags\u0020;20,name\u0020;jdk.jdi\u0020;flags\u0020;20 uses jdk/jshell/spi/ExecutionControlProvider,jdk/internal/editor/spi/BuildInEditorProvider provides interface\u0020;javax/tools/Tool\u0020;impls\u0020;jdk/internal/jshell/tool/JShellToolProvider,interface\u0020;jdk/jshell/spi/ExecutionControlProvider\u0020;impls\u0020;jdk/jshell/execution/JdiExecutionControlProvider\u005C;u002C;jdk/jshell/execution/LocalExecutionControlProvider\u005C;u002C;jdk/jshell/execution/FailOverExecutionControlProvider,interface\u0020;jdk/internal/io/JdkConsoleProvider\u0020;impls\u0020;jdk/jshell/execution/impl/ConsoleImpl$ConsoleProviderImpl target macos-aarch64 moduleMainClass jdk/internal/jshell/tool/JShellToolProvider flags 8000 + +class name jdk/jshell/SourceCodeAnalysis +header extends java/lang/Object nestMembers jdk/jshell/SourceCodeAnalysis$Attribute,jdk/jshell/SourceCodeAnalysis$Highlight,jdk/jshell/SourceCodeAnalysis$SnippetWrapper,jdk/jshell/SourceCodeAnalysis$QualifiedNames,jdk/jshell/SourceCodeAnalysis$Documentation,jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor,jdk/jshell/SourceCodeAnalysis$CompletionContext,jdk/jshell/SourceCodeAnalysis$CompletionState,jdk/jshell/SourceCodeAnalysis$ElementSuggestion,jdk/jshell/SourceCodeAnalysis$Suggestion,jdk/jshell/SourceCodeAnalysis$Completeness,jdk/jshell/SourceCodeAnalysis$CompletionInfo flags 421 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Attribute outerClass jdk/jshell/SourceCodeAnalysis innerClassName Attribute flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Highlight outerClass jdk/jshell/SourceCodeAnalysis innerClassName Highlight flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$SnippetWrapper outerClass jdk/jshell/SourceCodeAnalysis innerClassName SnippetWrapper flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$QualifiedNames outerClass jdk/jshell/SourceCodeAnalysis innerClassName QualifiedNames flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Documentation outerClass jdk/jshell/SourceCodeAnalysis innerClassName Documentation flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Suggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName Suggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Completeness outerClass jdk/jshell/SourceCodeAnalysis innerClassName Completeness flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionInfo outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionInfo flags 609 +method name completionSuggestions descriptor (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; flags 401 signature (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; + +class name jdk/jshell/SourceCodeAnalysis$CompletionContext +header extends java/lang/Enum nestHost jdk/jshell/SourceCodeAnalysis flags 4031 signature Ljava/lang/Enum; +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +field name ANNOTATION_ATTRIBUTE descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name NO_PAREN descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name TYPES_AS_ANNOTATIONS descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name QUALIFIED descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +method name values descriptor ()[Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 9 methodParameters 8000:null + +class name jdk/jshell/SourceCodeAnalysis$CompletionState +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis sealed true permittedSubclasses jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl flags 601 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +method name availableUsingSimpleName descriptor (Ljavax/lang/model/element/Element;)Z flags 401 +method name completionContext descriptor ()Ljava/util/Set; flags 401 signature ()Ljava/util/Set; +method name selectorType descriptor ()Ljavax/lang/model/type/TypeMirror; flags 401 +method name elementUtils descriptor ()Ljavax/lang/model/util/Elements; flags 401 +method name typeUtils descriptor ()Ljavax/lang/model/util/Types; flags 401 + +class name jdk/jshell/SourceCodeAnalysis$Documentation +method name activeParameterIndex descriptor ()I flags 1 + +class name jdk/jshell/SourceCodeAnalysis$ElementSuggestion +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis sealed true permittedSubclasses jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl flags 601 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +method name element descriptor ()Ljavax/lang/model/element/Element; flags 401 +method name keyword descriptor ()Ljava/lang/String; flags 401 +method name matchesType descriptor ()Z flags 401 +method name anchor descriptor ()I flags 401 +method name documentation descriptor ()Ljava/util/function/Supplier; flags 401 signature ()Ljava/util/function/Supplier; + +class name jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis flags 601 signature Ljava/lang/Object; +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +method name convert descriptor (Ljdk/jshell/SourceCodeAnalysis$CompletionState;Ljava/util/List;)Ljava/util/List; flags 401 signature (Ljdk/jshell/SourceCodeAnalysis$CompletionState;Ljava/util/List<+Ljdk/jshell/SourceCodeAnalysis$ElementSuggestion;>;)Ljava/util/List; + +class name jdk/jshell/SourceCodeAnalysisImpl +header extends jdk/jshell/SourceCodeAnalysis nestMembers jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl,jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl flags 20 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Completeness outerClass jdk/jshell/SourceCodeAnalysis innerClassName Completeness flags 4019 +innerclass innerClass com/sun/source/tree/Tree$Kind outerClass com/sun/source/tree/Tree innerClassName Kind flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$QualifiedNames outerClass jdk/jshell/SourceCodeAnalysis innerClassName QualifiedNames flags 19 +innerclass innerClass javax/tools/JavaFileManager$Location outerClass javax/tools/JavaFileManager innerClassName Location flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionInfo outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionInfo flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Documentation outerClass jdk/jshell/SourceCodeAnalysis innerClassName Documentation flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Highlight outerClass jdk/jshell/SourceCodeAnalysis innerClassName Highlight flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Attribute outerClass jdk/jshell/SourceCodeAnalysis innerClassName Attribute flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass java/lang/Thread$UncaughtExceptionHandler outerClass java/lang/Thread innerClassName UncaughtExceptionHandler flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Suggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName Suggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$SnippetWrapper outerClass jdk/jshell/SourceCodeAnalysis innerClassName SnippetWrapper flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name analyzeCompletion descriptor (Ljava/lang/String;)Ljdk/jshell/SourceCodeAnalysis$CompletionInfo; flags 1 +method name completionSuggestions descriptor (Ljava/lang/String;I[I)Ljava/util/List; flags 1 signature (Ljava/lang/String;I[I)Ljava/util/List; +method name completionSuggestions descriptor (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; flags 1 signature (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; +method name wrapper descriptor (Ljdk/jshell/Snippet;)Ljdk/jshell/SourceCodeAnalysis$SnippetWrapper; flags 1 +method name wrappers descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name sourceToSnippets descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name dependents descriptor (Ljdk/jshell/Snippet;)Ljava/util/Collection; flags 1 signature (Ljdk/jshell/Snippet;)Ljava/util/Collection; +method name highlights descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name documentation descriptor (Ljava/lang/String;IZ)Ljava/util/List; flags 1 signature (Ljava/lang/String;IZ)Ljava/util/List; +method name close descriptor ()V flags 1 +method name analyzeType descriptor (Ljava/lang/String;I)Ljava/lang/String; flags 1 +method name listQualifiedNames descriptor (Ljava/lang/String;I)Ljdk/jshell/SourceCodeAnalysis$QualifiedNames; flags 1 +method name suspendIndexing descriptor ()V flags 1 +method name resumeIndexing descriptor ()V flags 1 +method name waitBackgroundTaskFinished descriptor ()V thrownTypes java/lang/Exception flags 1 +method name waitCurrentBackgroundTasksFinished descriptor ()V thrownTypes java/lang/Exception flags 9 + +class name jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl +header extends java/lang/Object implements jdk/jshell/SourceCodeAnalysis$CompletionState nestHost jdk/jshell/SourceCodeAnalysisImpl flags 30 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +method name descriptor (Ljava/util/Collection;Ljava/util/Set;Ljavax/lang/model/type/TypeMirror;Ljavax/lang/model/util/Elements;Ljavax/lang/model/util/Types;)V flags 1 signature (Ljava/util/Collection<+Ljavax/lang/model/element/Element;>;Ljava/util/Set;Ljavax/lang/model/type/TypeMirror;Ljavax/lang/model/util/Elements;Ljavax/lang/model/util/Types;)V +method name availableUsingSimpleName descriptor (Ljavax/lang/model/element/Element;)Z flags 1 +method name completionContext descriptor ()Ljava/util/Set; flags 1 signature ()Ljava/util/Set; +method name selectorType descriptor ()Ljavax/lang/model/type/TypeMirror; flags 1 +method name elementUtils descriptor ()Ljavax/lang/model/util/Elements; flags 1 +method name typeUtils descriptor ()Ljavax/lang/model/util/Types; flags 1 + +class name jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl +header extends java/lang/Record implements jdk/jshell/SourceCodeAnalysis$ElementSuggestion nestHost jdk/jshell/SourceCodeAnalysisImpl record true flags 30 +recordcomponent name element descriptor Ljavax/lang/model/element/Element; +recordcomponent name keyword descriptor Ljava/lang/String; +recordcomponent name matchesType descriptor Z +recordcomponent name anchor descriptor I +recordcomponent name documentation descriptor Ljava/util/function/Supplier; signature Ljava/util/function/Supplier; +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name toString descriptor ()Ljava/lang/String; flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name element descriptor ()Ljavax/lang/model/element/Element; flags 1 +method name keyword descriptor ()Ljava/lang/String; flags 1 +method name matchesType descriptor ()Z flags 1 +method name anchor descriptor ()I flags 1 +method name documentation descriptor ()Ljava/util/function/Supplier; flags 1 signature ()Ljava/util/function/Supplier; + +class name jdk/jshell/execution/LocalExecutionControl +header extends jdk/jshell/execution/DirectExecutionControl flags 21 +innerclass innerClass jdk/jshell/spi/ExecutionControl$ClassBytecodes outerClass jdk/jshell/spi/ExecutionControl innerClassName ClassBytecodes flags 19 +innerclass innerClass java/lang/classfile/ClassFile$Option outerClass java/lang/classfile/ClassFile innerClassName Option flags 609 +innerclass innerClass java/lang/classfile/ClassFile$ClassHierarchyResolverOption outerClass java/lang/classfile/ClassFile innerClassName ClassHierarchyResolverOption flags 609 +innerclass innerClass jdk/jshell/spi/ExecutionControl$StoppedException outerClass jdk/jshell/spi/ExecutionControl innerClassName StoppedException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$InternalException outerClass jdk/jshell/spi/ExecutionControl innerClassName InternalException flags 9 +innerclass innerClass java/lang/classfile/CodeBuilder$BlockCodeBuilder outerClass java/lang/classfile/CodeBuilder innerClassName BlockCodeBuilder flags 609 +innerclass innerClass jdk/jshell/spi/ExecutionControl$ClassInstallException outerClass jdk/jshell/spi/ExecutionControl innerClassName ClassInstallException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$NotImplementedException outerClass jdk/jshell/spi/ExecutionControl innerClassName NotImplementedException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$EngineTerminationException outerClass jdk/jshell/spi/ExecutionControl innerClassName EngineTerminationException flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt new file mode 100644 index 00000000000..c8b83f6800b --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt @@ -0,0 +1,34 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +-module name jdk.jsobject + +-class name netscape/javascript/JSException + +-class name netscape/javascript/JSObject + diff --git a/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt new file mode 100644 index 00000000000..71d9c3fea14 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.localedata +header requires name\u0020;java.base\u0020;flags\u0020;8000 provides interface\u0020;sun/util/locale/provider/LocaleDataMetaInfo\u0020;impls\u0020;sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo\u005C;u002C;sun/util/resources/provider/NonBaseLocaleDataMetaInfo,interface\u0020;sun/util/resources/LocaleData$LocaleDataResourceBundleProvider\u0020;impls\u0020;sun/util/resources/provider/LocaleDataProvider target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/symbols b/src/jdk.compiler/share/data/symbols/symbols index 34619bed887..4bc5127310f 100644 --- a/src/jdk.compiler/share/data/symbols/symbols +++ b/src/jdk.compiler/share/data/symbols/symbols @@ -29,7 +29,7 @@ #command used to generate this file: #build.tools.symbolgenerator.CreateSymbols build-description-incremental symbols include.list # -generate platforms 8:9:A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P +generate platforms 8:9:A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q platform version 8 files java.activation-8.sym.txt:java.base-8.sym.txt:java.compiler-8.sym.txt:java.corba-8.sym.txt:java.datatransfer-8.sym.txt:java.desktop-8.sym.txt:java.instrument-8.sym.txt:java.logging-8.sym.txt:java.management-8.sym.txt:java.management.rmi-8.sym.txt:java.naming-8.sym.txt:java.prefs-8.sym.txt:java.rmi-8.sym.txt:java.scripting-8.sym.txt:java.security.jgss-8.sym.txt:java.security.sasl-8.sym.txt:java.sql-8.sym.txt:java.sql.rowset-8.sym.txt:java.transaction-8.sym.txt:java.xml-8.sym.txt:java.xml.bind-8.sym.txt:java.xml.crypto-8.sym.txt:java.xml.ws-8.sym.txt:java.xml.ws.annotation-8.sym.txt:jdk.httpserver-8.sym.txt:jdk.management-8.sym.txt:jdk.net-8.sym.txt:jdk.scripting.nashorn-8.sym.txt:jdk.sctp-8.sym.txt:jdk.security.auth-8.sym.txt:jdk.security.jgss-8.sym.txt platform version 9 base 8 files java.activation-9.sym.txt:java.base-9.sym.txt:java.compiler-9.sym.txt:java.corba-9.sym.txt:java.datatransfer-9.sym.txt:java.desktop-9.sym.txt:java.instrument-9.sym.txt:java.logging-9.sym.txt:java.management-9.sym.txt:java.management.rmi-9.sym.txt:java.naming-9.sym.txt:java.prefs-9.sym.txt:java.rmi-9.sym.txt:java.scripting-9.sym.txt:java.se-9.sym.txt:java.se.ee-9.sym.txt:java.security.jgss-9.sym.txt:java.security.sasl-9.sym.txt:java.smartcardio-9.sym.txt:java.sql-9.sym.txt:java.sql.rowset-9.sym.txt:java.transaction-9.sym.txt:java.xml-9.sym.txt:java.xml.bind-9.sym.txt:java.xml.crypto-9.sym.txt:java.xml.ws-9.sym.txt:java.xml.ws.annotation-9.sym.txt:jdk.accessibility-9.sym.txt:jdk.attach-9.sym.txt:jdk.charsets-9.sym.txt:jdk.compiler-9.sym.txt:jdk.crypto.cryptoki-9.sym.txt:jdk.crypto.ec-9.sym.txt:jdk.dynalink-9.sym.txt:jdk.editpad-9.sym.txt:jdk.hotspot.agent-9.sym.txt:jdk.httpserver-9.sym.txt:jdk.incubator.httpclient-9.sym.txt:jdk.jartool-9.sym.txt:jdk.javadoc-9.sym.txt:jdk.jcmd-9.sym.txt:jdk.jconsole-9.sym.txt:jdk.jdeps-9.sym.txt:jdk.jdi-9.sym.txt:jdk.jdwp.agent-9.sym.txt:jdk.jlink-9.sym.txt:jdk.jshell-9.sym.txt:jdk.jsobject-9.sym.txt:jdk.jstatd-9.sym.txt:jdk.localedata-9.sym.txt:jdk.management-9.sym.txt:jdk.management.agent-9.sym.txt:jdk.naming.dns-9.sym.txt:jdk.naming.rmi-9.sym.txt:jdk.net-9.sym.txt:jdk.pack-9.sym.txt:jdk.policytool-9.sym.txt:jdk.rmic-9.sym.txt:jdk.scripting.nashorn-9.sym.txt:jdk.sctp-9.sym.txt:jdk.security.auth-9.sym.txt:jdk.security.jgss-9.sym.txt:jdk.unsupported-9.sym.txt:jdk.xml.dom-9.sym.txt:jdk.zipfs-9.sym.txt platform version A base 9 files java.activation-A.sym.txt:java.base-A.sym.txt:java.compiler-A.sym.txt:java.corba-A.sym.txt:java.datatransfer-A.sym.txt:java.desktop-A.sym.txt:java.instrument-A.sym.txt:java.logging-A.sym.txt:java.management-A.sym.txt:java.management.rmi-A.sym.txt:java.naming-A.sym.txt:java.prefs-A.sym.txt:java.rmi-A.sym.txt:java.scripting-A.sym.txt:java.se-A.sym.txt:java.se.ee-A.sym.txt:java.security.jgss-A.sym.txt:java.security.sasl-A.sym.txt:java.smartcardio-A.sym.txt:java.sql-A.sym.txt:java.sql.rowset-A.sym.txt:java.transaction-A.sym.txt:java.xml-A.sym.txt:java.xml.bind-A.sym.txt:java.xml.crypto-A.sym.txt:java.xml.ws-A.sym.txt:java.xml.ws.annotation-A.sym.txt:jdk.accessibility-A.sym.txt:jdk.attach-A.sym.txt:jdk.charsets-A.sym.txt:jdk.compiler-A.sym.txt:jdk.crypto.cryptoki-A.sym.txt:jdk.crypto.ec-A.sym.txt:jdk.dynalink-A.sym.txt:jdk.editpad-A.sym.txt:jdk.hotspot.agent-A.sym.txt:jdk.httpserver-A.sym.txt:jdk.incubator.httpclient-A.sym.txt:jdk.jartool-A.sym.txt:jdk.javadoc-A.sym.txt:jdk.jcmd-A.sym.txt:jdk.jconsole-A.sym.txt:jdk.jdeps-A.sym.txt:jdk.jdi-A.sym.txt:jdk.jdwp.agent-A.sym.txt:jdk.jlink-A.sym.txt:jdk.jshell-A.sym.txt:jdk.jsobject-A.sym.txt:jdk.jstatd-A.sym.txt:jdk.localedata-A.sym.txt:jdk.management-A.sym.txt:jdk.management.agent-A.sym.txt:jdk.naming.dns-A.sym.txt:jdk.naming.rmi-A.sym.txt:jdk.net-A.sym.txt:jdk.pack-A.sym.txt:jdk.policytool-A.sym.txt:jdk.rmic-A.sym.txt:jdk.scripting.nashorn-A.sym.txt:jdk.sctp-A.sym.txt:jdk.security.auth-A.sym.txt:jdk.security.jgss-A.sym.txt:jdk.unsupported-A.sym.txt:jdk.xml.dom-A.sym.txt:jdk.zipfs-A.sym.txt @@ -48,3 +48,4 @@ platform version M base L files java.base-M.sym.txt:java.compiler-M.sym.txt:java platform version N base M files java.base-N.sym.txt:java.compiler-N.sym.txt:java.desktop-N.sym.txt:java.management-N.sym.txt:java.management.rmi-N.sym.txt:jdk.compiler-N.sym.txt:jdk.httpserver-N.sym.txt:jdk.incubator.foreign-N.sym.txt:jdk.javadoc-N.sym.txt:jdk.jshell-N.sym.txt:jdk.localedata-N.sym.txt:jdk.unsupported-N.sym.txt platform version O base N files java.base-O.sym.txt:java.compiler-O.sym.txt:java.datatransfer-O.sym.txt:java.desktop-O.sym.txt:java.instrument-O.sym.txt:java.logging-O.sym.txt:java.management-O.sym.txt:java.management.rmi-O.sym.txt:java.naming-O.sym.txt:java.net.http-O.sym.txt:java.prefs-O.sym.txt:java.rmi-O.sym.txt:java.scripting-O.sym.txt:java.se-O.sym.txt:java.security.jgss-O.sym.txt:java.security.sasl-O.sym.txt:java.smartcardio-O.sym.txt:java.sql-O.sym.txt:java.sql.rowset-O.sym.txt:java.transaction.xa-O.sym.txt:java.xml-O.sym.txt:java.xml.crypto-O.sym.txt:jdk.accessibility-O.sym.txt:jdk.attach-O.sym.txt:jdk.charsets-O.sym.txt:jdk.compiler-O.sym.txt:jdk.crypto.cryptoki-O.sym.txt:jdk.dynalink-O.sym.txt:jdk.editpad-O.sym.txt:jdk.hotspot.agent-O.sym.txt:jdk.httpserver-O.sym.txt:jdk.incubator.foreign-O.sym.txt:jdk.incubator.vector-O.sym.txt:jdk.jartool-O.sym.txt:jdk.javadoc-O.sym.txt:jdk.jcmd-O.sym.txt:jdk.jconsole-O.sym.txt:jdk.jdeps-O.sym.txt:jdk.jdi-O.sym.txt:jdk.jdwp.agent-O.sym.txt:jdk.jfr-O.sym.txt:jdk.jlink-O.sym.txt:jdk.jpackage-O.sym.txt:jdk.jshell-O.sym.txt:jdk.jsobject-O.sym.txt:jdk.jstatd-O.sym.txt:jdk.localedata-O.sym.txt:jdk.management-O.sym.txt:jdk.management.agent-O.sym.txt:jdk.management.jfr-O.sym.txt:jdk.naming.dns-O.sym.txt:jdk.naming.rmi-O.sym.txt:jdk.net-O.sym.txt:jdk.nio.mapmode-O.sym.txt:jdk.sctp-O.sym.txt:jdk.security.auth-O.sym.txt:jdk.security.jgss-O.sym.txt:jdk.unsupported-O.sym.txt:jdk.xml.dom-O.sym.txt:jdk.zipfs-O.sym.txt platform version P base O files java.base-P.sym.txt:java.compiler-P.sym.txt:java.desktop-P.sym.txt:java.logging-P.sym.txt:java.management-P.sym.txt:java.net.http-P.sym.txt:java.security.jgss-P.sym.txt:java.xml.crypto-P.sym.txt:jdk.attach-P.sym.txt:jdk.compiler-P.sym.txt:jdk.incubator.foreign-P.sym.txt:jdk.incubator.vector-P.sym.txt:jdk.jdi-P.sym.txt:jdk.jfr-P.sym.txt:jdk.jpackage-P.sym.txt:jdk.jshell-P.sym.txt:jdk.net-P.sym.txt:jdk.security.jgss-P.sym.txt +platform version Q base P files java.base-Q.sym.txt:java.compiler-Q.sym.txt:java.desktop-Q.sym.txt:java.management-Q.sym.txt:java.net.http-Q.sym.txt:jdk.httpserver-Q.sym.txt:jdk.incubator.vector-Q.sym.txt:jdk.jartool-Q.sym.txt:jdk.jdeps-Q.sym.txt:jdk.jfr-Q.sym.txt:jdk.jlink-Q.sym.txt:jdk.jshell-Q.sym.txt:jdk.jsobject-Q.sym.txt:jdk.localedata-Q.sym.txt diff --git a/src/jdk.compiler/share/man/javac.md b/src/jdk.compiler/share/man/javac.md index 1822931bf40..c749ca4da10 100644 --- a/src/jdk.compiler/share/man/javac.md +++ b/src/jdk.compiler/share/man/javac.md @@ -611,7 +611,7 @@ file system locations may be directories, JAR files or JMOD files. - `incubating`: Warns about the use of incubating modules. - `lossy-conversions`: Warns about possible lossy conversions - in compound assignment. + in compound assignment and bit shift operations. - `missing-explicit-ctor`: Warns about missing explicit constructors in public and protected classes in exported packages. diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java index 91302dba0f6..f935c56b536 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -48,7 +48,7 @@ public class NMethod extends CodeBlob { /** Offsets for different nmethod parts */ private static CIntegerField exceptionOffsetField; - private static CIntegerField deoptHandlerOffsetField; + private static CIntegerField deoptHandlerEntryOffsetField; private static CIntegerField origPCOffsetField; private static CIntegerField stubOffsetField; private static CIntField handlerTableOffsetField; @@ -86,7 +86,7 @@ public class NMethod extends CodeBlob { immutableDataField = type.getAddressField("_immutable_data"); immutableDataSizeField = type.getCIntegerField("_immutable_data_size"); exceptionOffsetField = type.getCIntegerField("_exception_offset"); - deoptHandlerOffsetField = type.getCIntegerField("_deopt_handler_offset"); + deoptHandlerEntryOffsetField = type.getCIntegerField("_deopt_handler_entry_offset"); origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); stubOffsetField = type.getCIntegerField("_stub_offset"); scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); @@ -121,16 +121,16 @@ public class NMethod extends CodeBlob { public boolean isOSRMethod() { return getEntryBCI() != VM.getVM().getInvocationEntryBCI(); } /** Boundaries for different parts */ - public Address constantsBegin() { return contentBegin(); } - public Address constantsEnd() { return codeBegin(); } - public Address instsBegin() { return codeBegin(); } - public Address instsEnd() { return headerBegin().addOffsetTo(getStubOffset()); } - public Address exceptionBegin() { return headerBegin().addOffsetTo(getExceptionOffset()); } - public Address deoptHandlerBegin() { return headerBegin().addOffsetTo(getDeoptHandlerOffset()); } - public Address stubBegin() { return headerBegin().addOffsetTo(getStubOffset()); } - public Address stubEnd() { return dataBegin(); } - public Address oopsBegin() { return dataBegin(); } - public Address oopsEnd() { return dataEnd(); } + public Address constantsBegin() { return contentBegin(); } + public Address constantsEnd() { return codeBegin(); } + public Address instsBegin() { return codeBegin(); } + public Address instsEnd() { return headerBegin().addOffsetTo(getStubOffset()); } + public Address exceptionBegin() { return headerBegin().addOffsetTo(getExceptionOffset()); } + public Address deoptHandlerEntry() { return headerBegin().addOffsetTo(getDeoptHandlerEntryOffset()); } + public Address stubBegin() { return headerBegin().addOffsetTo(getStubOffset()); } + public Address stubEnd() { return dataBegin(); } + public Address oopsBegin() { return dataBegin(); } + public Address oopsEnd() { return dataEnd(); } public Address immutableDataBegin() { return immutableDataField.getValue(addr); } public Address immutableDataEnd() { return immutableDataBegin().addOffsetTo(getImmutableDataSize()); } @@ -262,7 +262,7 @@ public class NMethod extends CodeBlob { // Deopt // Return true is the PC is one would expect if the frame is being deopted. public boolean isDeoptPc (Address pc) { return isDeoptEntry(pc); } - public boolean isDeoptEntry (Address pc) { return pc == deoptHandlerBegin(); } + public boolean isDeoptEntry (Address pc) { return pc == deoptHandlerEntry(); } /** Tells whether frames described by this nmethod can be deoptimized. Note: native wrappers cannot be deoptimized. */ @@ -490,7 +490,7 @@ public class NMethod extends CodeBlob { private int getEntryBCI() { return (int) entryBCIField .getValue(addr); } private int getExceptionOffset() { return (int) exceptionOffsetField .getValue(addr); } - private int getDeoptHandlerOffset() { return (int) deoptHandlerOffsetField .getValue(addr); } + private int getDeoptHandlerEntryOffset() { return (int) deoptHandlerEntryOffsetField .getValue(addr); } private int getStubOffset() { return (int) stubOffsetField .getValue(addr); } private int getScopesDataOffset() { return (int) scopesDataOffsetField .getValue(addr); } private int getScopesPCsOffset() { return (int) scopesPCsOffsetField .getValue(addr); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java index 10f6881d010..efbb613994d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,9 @@ package sun.jvm.hotspot.debugger.bsd; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.stream.IntStream; import sun.jvm.hotspot.debugger.Address; import sun.jvm.hotspot.debugger.DebuggerBase; @@ -75,10 +77,11 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { // CDebugger support private BsdCDebugger cdbg; - // threadList and loadObjectList are filled by attach0 method - private List threadList; + // loadObjectList is filled by attach0 method private List loadObjectList; + private List javaThreadList; + // called by native method lookupByAddress0 private ClosestSymbol createClosestSymbol(String name, long offset) { return new ClosestSymbol(name, offset); @@ -241,10 +244,21 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { } } + private void fillJavaThreadList() { + // TODO: thread list on macOS is now supported for corefile only. + if (!isCore && isDarwin) { + javaThreadList = Collections.emptyList(); + } else { + Threads threads = VM.getVM().getThreads(); + javaThreadList = IntStream.range(0, threads.getNumberOfThreads()) + .mapToObj(threads::getJavaThreadAt) + .toList(); + } + } + /** From the Debugger interface via JVMDebugger */ public synchronized void attach(int processID) throws DebuggerException { checkAttached(); - threadList = new ArrayList<>(); loadObjectList = new ArrayList<>(); class AttachTask implements WorkerThreadTask { int pid; @@ -264,7 +278,6 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** From the Debugger interface via JVMDebugger */ public synchronized void attach(String execName, String coreName) { checkAttached(); - threadList = new ArrayList<>(); loadObjectList = new ArrayList<>(); attach0(execName, coreName); attached = true; @@ -278,7 +291,7 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { return false; } - threadList = null; + javaThreadList = null; loadObjectList = null; if (isCore) { @@ -492,7 +505,12 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** From the BsdCDebugger interface */ public List getThreadList() { requireAttach(); - return threadList; + if (javaThreadList == null) { + fillJavaThreadList(); + } + return javaThreadList.stream() + .map(JavaThread::getThreadProxy) + .toList(); } /** From the BsdCDebugger interface */ @@ -561,21 +579,19 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /** this functions used for core file reading and called from native attach0, it returns an array of long integers as [thread_id, stack_start, stack_end, thread_id, stack_start, stack_end, ....] for - all java threads recorded in Threads. Also adds the ThreadProxy to threadList */ + all java threads recorded in Threads. */ public long[] getJavaThreadsInfo() { requireAttach(); - Threads threads = VM.getVM().getThreads(); - int len = threads.getNumberOfThreads(); - long[] result = new long[len * 3]; // triple + if (javaThreadList == null) { + fillJavaThreadList(); + } + long[] result = new long[javaThreadList.size() * 3]; // triple long beg, end; int i = 0; - for (int k = 0; k < threads.getNumberOfThreads(); k++) { - JavaThread t = threads.getJavaThreadAt(k); + for (var t : javaThreadList) { end = t.getStackBaseValue(); beg = end - t.getStackSize(); - BsdThread bsdt = (BsdThread)t.getThreadProxy(); - long uid = bsdt.getUniqueThreadId(); - if (threadList != null) threadList.add(bsdt); + long uid = ((BsdThread)t.getThreadProxy()).getUniqueThreadId(); result[i] = uid; result[i + 1] = beg; result[i + 2] = end; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java index 47f41fe1383..bc366ef02b5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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,8 @@ package sun.jvm.hotspot.debugger.cdbg; import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.utilities.*; /** Models a "C" programming language frame on the stack -- really just an arbitrary frame with hooks to access C and C++ debug @@ -37,7 +39,7 @@ public interface CFrame { public CFrame sender(ThreadProxy th); /** Find sender frame with given FP and PC */ - public default CFrame sender(ThreadProxy th, Address fp, Address pc) { + public default CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) { return sender(th); } @@ -70,4 +72,9 @@ public interface CFrame { /** Visit all local variables in this frame if debug information is available. Automatically descends into compound types and arrays. */ public void iterateLocals(ObjectVisitor v); + + /** Get Frame instance assosiated with this CFrame. */ + public default Frame toFrame() { + throw new UnsupportedPlatformException(); + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java index 894e31949b2..e3543503216 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -81,9 +81,11 @@ class LinuxCDebugger implements CDebugger { String cpu = dbg.getCPU(); if (cpu.equals("amd64")) { AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(AMD64ThreadContext.RSP); + if (sp == null) return null; Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP); if (pc == null) return null; - return LinuxAMD64CFrame.getTopFrame(dbg, pc, context); + return LinuxAMD64CFrame.getTopFrame(dbg, sp, pc, context); } else if (cpu.equals("ppc64")) { PPC64ThreadContext context = (PPC64ThreadContext) thread.getContext(); Address sp = context.getRegisterAsAddress(PPC64ThreadContext.SP); @@ -93,18 +95,22 @@ class LinuxCDebugger implements CDebugger { return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize()); } else if (cpu.equals("aarch64")) { AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(AARCH64ThreadContext.SP); + if (sp == null) return null; Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP); if (fp == null) return null; Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC); if (pc == null) return null; - return new LinuxAARCH64CFrame(dbg, fp, pc); + return new LinuxAARCH64CFrame(dbg, sp, fp, pc); } else if (cpu.equals("riscv64")) { RISCV64ThreadContext context = (RISCV64ThreadContext) thread.getContext(); + Address sp = context.getRegisterAsAddress(RISCV64ThreadContext.SP); + if (sp == null) return null; Address fp = context.getRegisterAsAddress(RISCV64ThreadContext.FP); if (fp == null) return null; Address pc = context.getRegisterAsAddress(RISCV64ThreadContext.PC); if (pc == null) return null; - return new LinuxRISCV64CFrame(dbg, fp, pc); + return new LinuxRISCV64CFrame(dbg, sp, fp, pc); } else { // Runtime exception thrown by LinuxThreadContextFactory if unknown cpu ThreadContext context = thread.getContext(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java index 93edb43eb82..5f76e6308e9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,10 +30,14 @@ import sun.jvm.hotspot.debugger.aarch64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.code.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.aarch64.*; public final class LinuxAARCH64CFrame extends BasicCFrame { - public LinuxAARCH64CFrame(LinuxDebugger dbg, Address fp, Address pc) { + public LinuxAARCH64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) { super(dbg.getCDebugger()); + this.sp = sp; this.fp = fp; this.pc = pc; this.dbg = dbg; @@ -55,11 +59,11 @@ public final class LinuxAARCH64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy thread) { - return sender(thread, null, null); + return sender(thread, null, null, null); } @Override - public CFrame sender(ThreadProxy thread, Address nextFP, Address nextPC) { + public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) { // Check fp // Skip if both nextFP and nextPC are given - do not need to load from fp. if (nextFP == null && nextPC == null) { @@ -86,7 +90,32 @@ public final class LinuxAARCH64CFrame extends BasicCFrame { if (nextPC == null) { return null; } - return new LinuxAARCH64CFrame(dbg, nextFP, nextPC); + + if (nextSP == null) { + CodeCache cc = VM.getVM().getCodeCache(); + CodeBlob currentBlob = cc.findBlobUnsafe(pc()); + + // This case is different from HotSpot. See JDK-8371194 for details. + if (currentBlob != null && (currentBlob.isContinuationStub() || currentBlob.isNativeMethod())) { + // Use FP since it should always be valid for these cases. + // TODO: These should be walked as Frames not CFrames. + nextSP = fp.addOffsetTo(2 * ADDRESS_SIZE); + } else { + CodeBlob codeBlob = cc.findBlobUnsafe(nextPC); + boolean useCodeBlob = codeBlob != null && codeBlob.getFrameSize() > 0; + nextSP = useCodeBlob ? nextFP.addOffsetTo((2 * ADDRESS_SIZE) - codeBlob.getFrameSize()) : nextFP; + } + } + if (nextSP == null) { + return null; + } + + return new LinuxAARCH64CFrame(dbg, nextSP, nextFP, nextPC); + } + + @Override + public Frame toFrame() { + return new AARCH64Frame(sp, fp, pc); } // package/class internals only diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index 9fa0fc20e99..612203634f3 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -29,10 +29,12 @@ import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.amd64.*; public final class LinuxAMD64CFrame extends BasicCFrame { - public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rip, ThreadContext context) { + public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rsp, Address rip, ThreadContext context) { Address libptr = dbg.findLibPtrByAddress(rip); Address cfa = context.getRegisterAsAddress(AMD64ThreadContext.RBP); DwarfParser dwarf = null; @@ -45,7 +47,7 @@ public final class LinuxAMD64CFrame extends BasicCFrame { // DWARF processing should succeed when the frame is native // but it might fail if Common Information Entry (CIE) has language // personality routine and/or Language Specific Data Area (LSDA). - return new LinuxAMD64CFrame(dbg, cfa, rip, dwarf, true); + return new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf, true); } cfa = context.getRegisterAsAddress(dwarf.getCFARegister()) @@ -53,19 +55,20 @@ public final class LinuxAMD64CFrame extends BasicCFrame { } return (cfa == null) ? null - : new LinuxAMD64CFrame(dbg, cfa, rip, dwarf); + : new LinuxAMD64CFrame(dbg, rsp, cfa, rip, dwarf); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf) { - this(dbg, cfa, rip, dwarf, false); + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf) { + this(dbg, rsp, cfa, rip, dwarf, false); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) { - this(dbg, cfa, rip, dwarf, finalFrame, false); + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) { + this(dbg, rsp, cfa, rip, dwarf, finalFrame, false); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame, boolean use1ByteBeforeToLookup) { + private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame, boolean use1ByteBeforeToLookup) { super(dbg.getCDebugger()); + this.rsp = rsp; this.cfa = cfa; this.rip = rip; this.dbg = dbg; @@ -107,7 +110,14 @@ public final class LinuxAMD64CFrame extends BasicCFrame { (!isNative || (isNative && nextCFA.greaterThan(cfa))); } - private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context, Address senderFP) { + private Address getNextRSP() { + // next RSP should be previous slot of return address. + var bp = dwarf == null ? cfa.addOffsetTo(ADDRESS_SIZE) // top of BP points callser BP + : cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA()); + return bp.addOffsetTo(ADDRESS_SIZE); + } + + private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context, Address senderFP, Address senderPC) { Address nextCFA; boolean isNative = false; @@ -115,13 +125,17 @@ public final class LinuxAMD64CFrame extends BasicCFrame { senderFP = cfa.getAddressAt(0); // RBP by default } - if (nextDwarf == null) { // Next frame is Java + if (VM.getVM().getCodeCache().contains(senderPC)) { // Next frame is Java nextCFA = (dwarf == null) ? senderFP // Current frame is Java : cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA()); // Current frame is Native } else { // Next frame is Native - if (dwarf == null) { // Current frame is Java + if (VM.getVM().getCodeCache().contains(pc())) { // Current frame is Java nextCFA = senderFP.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA()); } else { // Current frame is Native + if (nextDwarf == null) { // maybe runtime entrypoint (_start()) + throw new DebuggerException("nextDwarf is null even though native call"); + } + isNative = true; int nextCFAReg = nextDwarf.getCFARegister(); if (nextCFAReg == AMD64ThreadContext.RBP) { @@ -130,10 +144,7 @@ public final class LinuxAMD64CFrame extends BasicCFrame { Address nextRBP = rbp.getAddressAt(0); nextCFA = nextRBP.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA()); } else if (nextCFAReg == AMD64ThreadContext.RSP) { - // next RSP should be previous slot of return address. - Address nextRSP = cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA()) - .addOffsetTo(ADDRESS_SIZE); - nextCFA = nextRSP.addOffsetTo(nextDwarf.getCFAOffset()); + nextCFA = getNextRSP().addOffsetTo(nextDwarf.getCFAOffset()); } else { throw new DebuggerException("Unsupported CFA register: " + nextCFAReg); } @@ -153,17 +164,22 @@ public final class LinuxAMD64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy th) { - return sender(th, null, null); + return sender(th, null, null, null); } @Override - public CFrame sender(ThreadProxy th, Address fp, Address pc) { + public CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) { if (finalFrame) { return null; } ThreadContext context = th.getContext(); + Address nextRSP = sp != null ? sp : getNextRSP(); + if (nextRSP == null) { + return null; + } + Address nextPC = pc != null ? pc : getNextPC(dwarf != null); if (nextPC == null) { return null; @@ -183,13 +199,16 @@ public final class LinuxAMD64CFrame extends BasicCFrame { // DWARF processing should succeed when the frame is native // but it might fail if Common Information Entry (CIE) has language // personality routine and/or Language Specific Data Area (LSDA). - return new LinuxAMD64CFrame(dbg, null, nextPC, nextDwarf, true); + return null; } } - Address nextCFA = getNextCFA(nextDwarf, context, fp); - return nextCFA == null ? null - : new LinuxAMD64CFrame(dbg, nextCFA, nextPC, nextDwarf, false, fallback); + try { + Address nextCFA = getNextCFA(nextDwarf, context, fp, nextPC); + return new LinuxAMD64CFrame(dbg, nextRSP, nextCFA, nextPC, nextDwarf, false, fallback); + } catch (DebuggerException _) { + return null; + } } private DwarfParser createDwarfParser(Address pc) throws DebuggerException { @@ -210,8 +229,14 @@ public final class LinuxAMD64CFrame extends BasicCFrame { return nextDwarf; } + @Override + public Frame toFrame() { + return new AMD64Frame(rsp, cfa, rip); + } + // package/class internals only private static final int ADDRESS_SIZE = 8; + private Address rsp; private Address rip; private Address cfa; private LinuxDebugger dbg; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java index 424766fb1b4..c3724f14c2a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -29,6 +29,8 @@ import sun.jvm.hotspot.debugger.ppc64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.ppc64.*; public final class LinuxPPC64CFrame extends BasicCFrame { // package/class internals only @@ -71,6 +73,12 @@ public final class LinuxPPC64CFrame extends BasicCFrame { return new LinuxPPC64CFrame(dbg, nextSP, nextPC, address_size); } + @Override + public Frame toFrame() { + // 2nd arg (raw_fp) would be derived from sp in c'tor of PPC64Frame. + return new PPC64Frame(sp, null, pc); + } + public static int PPC64_STACK_BIAS = 0; private static int address_size; private Address pc; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java index 76f45891c47..65563be59ec 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -31,13 +31,17 @@ import sun.jvm.hotspot.debugger.riscv64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.basic.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.riscv64.*; public final class LinuxRISCV64CFrame extends BasicCFrame { private static final int C_FRAME_LINK_OFFSET = -2; private static final int C_FRAME_RETURN_ADDR_OFFSET = -1; + private static final int C_FRAME_SENDER_SP_OFFSET = 0; - public LinuxRISCV64CFrame(LinuxDebugger dbg, Address fp, Address pc) { + public LinuxRISCV64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) { super(dbg.getCDebugger()); + this.sp = sp; this.fp = fp; this.pc = pc; this.dbg = dbg; @@ -59,11 +63,11 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { @Override public CFrame sender(ThreadProxy thread) { - return sender(thread, null, null); + return sender(thread, null, null, null); } @Override - public CFrame sender(ThreadProxy thread, Address nextFP, Address nextPC) { + public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) { // Check fp // Skip if both nextFP and nextPC are given - do not need to load from fp. if (nextFP == null && nextPC == null) { @@ -77,6 +81,13 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { } } + if (nextSP == null) { + nextSP = fp.getAddressAt(C_FRAME_SENDER_SP_OFFSET * ADDRESS_SIZE); + } + if (nextSP == null) { + return null; + } + if (nextFP == null) { nextFP = fp.getAddressAt(C_FRAME_LINK_OFFSET * ADDRESS_SIZE); } @@ -91,7 +102,12 @@ public final class LinuxRISCV64CFrame extends BasicCFrame { return null; } - return new LinuxRISCV64CFrame(dbg, nextFP, nextPC); + return new LinuxRISCV64CFrame(dbg, nextSP, nextFP, nextPC); + } + + @Override + public Frame toFrame() { + return new RISCV64Frame(sp, fp, pc); } // package/class internals only diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java index 563d9d3ac4a..3a4ea5546a1 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java @@ -88,8 +88,11 @@ public class ConstantPool extends Metadata implements ClassConstants { private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("ConstantPool"); tags = type.getAddressField("_tags"); - operands = type.getAddressField("_operands"); cache = type.getAddressField("_cache"); + bsm_entries = type.getField("_bsm_entries").getOffset(); + Type bsmae_type = db.lookupType("BSMAttributeEntries"); + bsm_entries_offsets = bsmae_type.getAddressField("_offsets"); + bsm_entries_bootstrap_methods = bsmae_type.getAddressField("_bootstrap_methods"); poolHolder = new MetadataField(type.getAddressField("_pool_holder"), 0); length = new CIntField(type.getCIntegerField("_length"), 0); resolved_klasses = type.getAddressField("_resolved_klasses"); @@ -112,9 +115,11 @@ public class ConstantPool extends Metadata implements ClassConstants { public boolean isConstantPool() { return true; } private static AddressField tags; - private static AddressField operands; private static AddressField cache; private static AddressField resolved_klasses; + private static long bsm_entries; // Offset in the constantpool where the Bsm_Entries are found + private static AddressField bsm_entries_offsets; + private static AddressField bsm_entries_bootstrap_methods; private static MetadataField poolHolder; private static CIntField length; // number of elements in oop private static CIntField majorVersion; @@ -130,10 +135,6 @@ public class ConstantPool extends Metadata implements ClassConstants { private static int INDY_ARGV_OFFSET; public U1Array getTags() { return new U1Array(tags.getValue(getAddress())); } - public U2Array getOperands() { - Address addr = operands.getValue(getAddress()); - return VMObjectFactory.newObject(U2Array.class, addr); - } public ConstantPoolCache getCache() { Address addr = cache.getValue(getAddress()); return VMObjectFactory.newObject(ConstantPoolCache.class, addr); @@ -435,26 +436,23 @@ public class ConstantPool extends Metadata implements ClassConstants { return res; } + private U4Array getOffsets() { + Address a = getAddress().addOffsetTo(bsm_entries); + if (a == null) return null; + a = bsm_entries_offsets.getValue(a); + return VMObjectFactory.newObject(U4Array.class, a); + } + private U2Array getBootstrapMethods() { + Address a = getAddress().addOffsetTo(bsm_entries); + if (a == null) return null; + return VMObjectFactory.newObject(U2Array.class, bsm_entries_bootstrap_methods.getValue(a)); + } + public int getBootstrapMethodsCount() { - U2Array operands = getOperands(); + U4Array offsets = getOffsets(); int count = 0; - if (operands != null) { - // Operands array consists of two parts. First part is an array of 32-bit values which denote - // index of the bootstrap method data in the operands array. Note that elements of operands array are of type short. - // So each element of first part occupies two slots in the array. - // Second part is the bootstrap methods data. - // This layout allows us to get BSM count by getting the index of first BSM and dividing it by 2. - // - // The example below shows layout of operands array with 3 bootstrap methods. - // First part has 3 32-bit values indicating the index of the respective bootstrap methods in - // the operands array. - // The first BSM is at index 6. So the count in this case is 6/2=3. - // - // <-----first part----><-------second part-------> - // index: 0 2 4 6 i2 i3 - // operands: | 6 | i2 | i3 | bsm1 | bsm2 | bsm3 | - // - count = getOperandOffsetAt(operands, 0) / 2; + if (offsets != null) { + count = offsets.length(); } if (DEBUG) { System.err.println("ConstantPool.getBootstrapMethodsCount: count = " + count); @@ -463,12 +461,12 @@ public class ConstantPool extends Metadata implements ClassConstants { } public int getBootstrapMethodArgsCount(int bsmIndex) { - U2Array operands = getOperands(); + U4Array offs = getOffsets(); + U2Array bsms = getBootstrapMethods(); if (Assert.ASSERTS_ENABLED) { - Assert.that(operands != null, "Operands is not present"); + Assert.that(offs != null && bsms != null, "BSM attribute is not present"); } - int bsmOffset = getOperandOffsetAt(operands, bsmIndex); - int argc = operands.at(bsmOffset + INDY_ARGC_OFFSET); + int argc = bsms.at(offs.at(bsmIndex) + INDY_ARGC_OFFSET); if (DEBUG) { System.err.println("ConstantPool.getBootstrapMethodArgsCount: bsm index = " + bsmIndex + ", args count = " + argc); } @@ -476,15 +474,16 @@ public class ConstantPool extends Metadata implements ClassConstants { } public short[] getBootstrapMethodAt(int bsmIndex) { - U2Array operands = getOperands(); - if (operands == null) return null; // safety first - int basePos = getOperandOffsetAt(operands, bsmIndex); + U4Array offs = getOffsets(); + U2Array bsms = getBootstrapMethods(); + if (offs == null || bsms == null) return null; // safety first + int basePos = offs.at(bsmIndex); int argv = basePos + INDY_ARGV_OFFSET; - int argc = operands.at(basePos + INDY_ARGC_OFFSET); + int argc = getBootstrapMethodArgsCount(bsmIndex); int endPos = argv + argc; short[] values = new short[endPos - basePos]; for (int j = 0; j < values.length; j++) { - values[j] = operands.at(basePos+j); + values[j] = bsms.at(basePos+j); } return values; } @@ -773,8 +772,7 @@ public class ConstantPool extends Metadata implements ClassConstants { // Return the offset of the requested Bootstrap Method in the operands array private int getOperandOffsetAt(U2Array operands, int bsmIndex) { - return VM.getVM().buildIntFromShorts(operands.at(bsmIndex * 2), - operands.at(bsmIndex * 2 + 1)); + return 0; } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index 0cd743372d5..785bb85e640 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -62,6 +62,16 @@ public class InstanceKlass extends Klass { private static int CLASS_STATE_FULLY_INITIALIZED; private static int CLASS_STATE_INITIALIZATION_ERROR; + public long getAccessFlags() { return accessFlags.getValue(this); } + // Convenience routine + public AccessFlags getAccessFlagsObj() { return new AccessFlags(getAccessFlags()); } + + public boolean isPublic() { return getAccessFlagsObj().isPublic(); } + public boolean isFinal() { return getAccessFlagsObj().isFinal(); } + public boolean isInterface() { return getAccessFlagsObj().isInterface(); } + public boolean isAbstract() { return getAccessFlagsObj().isAbstract(); } + public boolean isSuper() { return getAccessFlagsObj().isSuper(); } + public boolean isSynthetic() { return getAccessFlagsObj().isSynthetic(); } private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("InstanceKlass"); @@ -88,6 +98,7 @@ public class InstanceKlass extends Klass { breakpoints = type.getAddressField("_breakpoints"); } headerSize = type.getSize(); + accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); // read internal field flags constants FIELD_FLAG_IS_INITIALIZED = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_initialized"); @@ -150,6 +161,7 @@ public class InstanceKlass extends Klass { private static CIntField initState; private static CIntField itableLen; private static CIntField nestHostIndex; + private static CIntField accessFlags; private static AddressField breakpoints; // type safe enum for ClassState from instanceKlass.hpp @@ -499,7 +511,7 @@ public class InstanceKlass extends Klass { } } - public boolean implementsInterface(Klass k) { + public boolean implementsInterface(InstanceKlass k) { if (Assert.ASSERTS_ENABLED) { Assert.that(k.isInterface(), "should not reach here"); } @@ -511,7 +523,7 @@ public class InstanceKlass extends Klass { return false; } - boolean computeSubtypeOf(Klass k) { + boolean computeSubtypeOf(InstanceKlass k) { if (k.isInterface()) { return implementsInterface(k); } else { @@ -535,6 +547,7 @@ public class InstanceKlass extends Klass { visitor.doCInt(nonstaticOopMapSize, true); visitor.doCInt(initState, true); visitor.doCInt(itableLen, true); + visitor.doCInt(accessFlags, true); } /* diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java index 1b8a9d0ef69..561c4683d29 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -57,7 +57,6 @@ public class Klass extends Metadata implements ClassConstants { superField = new MetadataField(type.getAddressField("_super"), 0); layoutHelper = new IntField(type.getJIntField("_layout_helper"), 0); name = type.getAddressField("_name"); - accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); try { traceIDField = type.getField("_trace_id"); } catch(Exception e) { @@ -95,7 +94,6 @@ public class Klass extends Metadata implements ClassConstants { private static MetadataField superField; private static IntField layoutHelper; private static AddressField name; - private static CIntField accessFlags; private static MetadataField subklass; private static MetadataField nextSibling; private static MetadataField nextLink; @@ -117,9 +115,6 @@ public class Klass extends Metadata implements ClassConstants { public Klass getJavaSuper() { return null; } public int getLayoutHelper() { return layoutHelper.getValue(this); } public Symbol getName() { return getSymbol(name); } - public long getAccessFlags() { return accessFlags.getValue(this); } - // Convenience routine - public AccessFlags getAccessFlagsObj(){ return new AccessFlags(getAccessFlags()); } public Klass getSubklassKlass() { return (Klass) subklass.getValue(this); } public Klass getNextSiblingKlass() { return (Klass) nextSibling.getValue(this); } public Klass getNextLinkKlass() { return (Klass) nextLink.getValue(this); } @@ -175,7 +170,6 @@ public class Klass extends Metadata implements ClassConstants { visitor.doMetadata(superField, true); visitor.doInt(layoutHelper, true); // visitor.doOop(name, true); - visitor.doCInt(accessFlags, true); visitor.doMetadata(subklass, true); visitor.doMetadata(nextSibling, true); visitor.doCInt(vtableLen, true); @@ -205,12 +199,4 @@ public class Klass extends Metadata implements ClassConstants { // The subclasses override this to produce the correct form, eg // Ljava/lang/String; For ArrayKlasses getName itself is the signature. public String signature() { return getName().asString(); } - - // Convenience routines - public boolean isPublic() { return getAccessFlagsObj().isPublic(); } - public boolean isFinal() { return getAccessFlagsObj().isFinal(); } - public boolean isInterface() { return getAccessFlagsObj().isInterface(); } - public boolean isAbstract() { return getAccessFlagsObj().isAbstract(); } - public boolean isSuper() { return getAccessFlagsObj().isSuper(); } - public boolean isSynthetic() { return getAccessFlagsObj().isSynthetic(); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java index a4cdb671959..c71cb3156ea 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -107,7 +107,7 @@ public class ObjectHeap { /** iterate objects of given Klass. param 'includeSubtypes' tells whether to * include objects of subtypes or not */ - public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k, boolean includeSubtypes) { + public void iterateObjectsOfKlass(HeapVisitor visitor, final InstanceKlass k, boolean includeSubtypes) { if (includeSubtypes) { if (k.isFinal()) { // do the simpler "exact" klass loop @@ -124,7 +124,7 @@ public class ObjectHeap { } /** iterate objects of given Klass (objects of subtypes included) */ - public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k) { + public void iterateObjectsOfKlass(HeapVisitor visitor, final InstanceKlass k) { iterateObjectsOfKlass(visitor, k, true); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java index fa28a96e333..c4abb3e946d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -64,7 +64,7 @@ public class ConcurrentLocksPrinter { private void fillLocks() { VM vm = VM.getVM(); SystemDictionary sysDict = vm.getSystemDictionary(); - Klass absOwnSyncKlass = sysDict.getAbstractOwnableSynchronizerKlass(); + InstanceKlass absOwnSyncKlass = sysDict.getAbstractOwnableSynchronizerKlass(); ObjectHeap heap = vm.getObjectHeap(); // may be not loaded at all if (absOwnSyncKlass != null) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java index 27efb631f79..ee9e0ecdafd 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java @@ -87,7 +87,7 @@ public abstract class Frame implements Cloneable { CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); if (cb != null && cb.isJavaMethod()) { NMethod nm = (NMethod) cb; - if (pc.equals(nm.deoptHandlerBegin())) { + if (pc.equals(nm.deoptHandlerEntry())) { if (Assert.ASSERTS_ENABLED) { Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java index 5ae4cb703b3..7233d508cbc 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java @@ -272,9 +272,7 @@ public class AARCH64Frame extends Frame { if (cb != null) { if (cb.isUpcallStub()) { return senderForUpcallStub(map, (UpcallStub)cb); - } else if (cb.isContinuationStub()) { - return senderForContinuationStub(map, cb); - } else { + } else if (cb.getFrameSize() > 0) { return senderForCompiledFrame(map, cb); } } @@ -389,7 +387,11 @@ public class AARCH64Frame extends Frame { if (Assert.ASSERTS_ENABLED) { Assert.that(cb.getFrameSize() > 0, "must have non-zero frame size"); } - Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize()); + + // TODO: senderSP should consider not only PreserveFramePointer but also _sp_is_trusted. + Address senderSP = !VM.getVM().getCommandLineBooleanFlag("PreserveFramePointer") + ? getUnextendedSP().addOffsetTo(cb.getFrameSize()) + : getSenderSP(); // The return_address is always the word on the stack Address senderPC = stripPAC(senderSP.getAddressAt(-1 * VM.getVM().getAddressSize())); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java index 360f62a253d..fa9d50160e1 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java @@ -272,9 +272,7 @@ public class AMD64Frame extends Frame { if (cb != null) { if (cb.isUpcallStub()) { return senderForUpcallStub(map, (UpcallStub)cb); - } else if (cb.isContinuationStub()) { - return senderForContinuationStub(map, cb); - } else { + } else if (cb.getFrameSize() > 0) { return senderForCompiledFrame(map, cb); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java index b7c470e3477..0e65a41c571 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,7 +90,7 @@ public class ClassLoaderStats extends Tool { VM vm = VM.getVM(); ObjectHeap heap = vm.getObjectHeap(); - Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); + InstanceKlass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); try { heap.iterateObjectsOfKlass(new DefaultHeapVisitor() { public boolean doObj(Oop oop) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java index 9865fbbe0f2..29d2954efdc 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java @@ -70,7 +70,6 @@ public class PStack extends Tool { if (cdbg != null) { ConcurrentLocksPrinter concLocksPrinter = null; // compute and cache java Vframes. - initJFrameCache(); if (concurrentLocks) { concLocksPrinter = new ConcurrentLocksPrinter(out); } @@ -96,6 +95,7 @@ public class PStack extends Tool { return; } final boolean cdbgCanDemangle = cdbg.canDemangle(); + Map proxyToThread = createProxyToThread();; String fillerForAddress = " ".repeat(2 + 2 * (int) VM.getVM().getAddressSize()) + "\t"; for (Iterator itr = l.iterator() ; itr.hasNext();) { ThreadProxy th = itr.next(); @@ -109,6 +109,7 @@ public class PStack extends Tool { jthread.printThreadInfoOn(out); } while (f != null) { + Address senderSP = null; Address senderFP = null; Address senderPC = null; ClosestSymbol sym = f.closestSymbolToPC(); @@ -131,7 +132,7 @@ public class PStack extends Tool { // check interpreter frame Interpreter interp = VM.getVM().getInterpreter(); if (interp.contains(pc)) { - nameInfo = getJavaNames(th, f.localVariableBase()); + nameInfo = getJavaNames(jthread, f); // print codelet name if we can't determine method if (nameInfo == null || nameInfo.names() == null || nameInfo.names().length == 0) { out.print(" "); @@ -156,7 +157,7 @@ public class PStack extends Tool { } out.println(" (Native method)"); } else { - nameInfo = getJavaNames(th, f.localVariableBase()); + nameInfo = getJavaNames(jthread, f); // just print compiled code, if can't determine method if (nameInfo == null || nameInfo.names() == null || nameInfo.names().length == 0) { out.println(""); @@ -164,6 +165,12 @@ public class PStack extends Tool { } } else { out.println("<" + cb.getName() + ">"); + if (cb.getFrameSize() > 0) { + Frame senderFrame = f.toFrame().sender(jthread.newRegisterMap(true)); + senderSP = senderFrame.getSP(); + senderFP = senderFrame.getFP(); + senderPC = senderFrame.getPC(); + } } } else { printUnknown(out); @@ -180,11 +187,12 @@ public class PStack extends Tool { out.println(nameInfo.names()[i]); } } + senderSP = nameInfo.senderSP(); senderFP = nameInfo.senderFP(); senderPC = nameInfo.senderPC(); } } - f = f.sender(th, senderFP, senderPC); + f = f.sender(th, senderSP, senderFP, senderPC); } } catch (Exception exp) { exp.printStackTrace(); @@ -212,95 +220,74 @@ public class PStack extends Tool { } // -- Internals only below this point - private Map jframeCache; - private Map proxyToThread; private PrintStream out; private boolean verbose; private boolean concurrentLocks; - private void initJFrameCache() { - // cache frames for subsequent reference - jframeCache = new HashMap<>(); - proxyToThread = new HashMap<>(); + private Map createProxyToThread() { + Map proxyToThread = new HashMap<>(); Threads threads = VM.getVM().getThreads(); for (int i = 0; i < threads.getNumberOfThreads(); i++) { - JavaThread cur = threads.getJavaThreadAt(i); - List tmp = new ArrayList<>(10); - try { - for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { - tmp.add(vf); - } - } catch (Exception exp) { - // may be we may get frames for other threads, continue - // after printing stack trace. - exp.printStackTrace(); - } - JavaVFrame[] jvframes = tmp.toArray(new JavaVFrame[0]); - jframeCache.put(cur.getThreadProxy(), jvframes); - proxyToThread.put(cur.getThreadProxy(), cur); + JavaThread jthread = threads.getJavaThreadAt(i); + proxyToThread.put(jthread.getThreadProxy(), jthread); } + return proxyToThread; } private void printUnknown(PrintStream out) { out.println("\t????????"); } - private static record JavaNameInfo(String[] names, Address senderFP, Address senderPC) {}; - - private JavaNameInfo getJavaNames(ThreadProxy th, Address fp) { - if (fp == null) { - return null; - } - JavaVFrame[] jvframes = jframeCache.get(th); - if (jvframes == null) return null; // not a java thread + private static record JavaNameInfo(String[] names, Address senderSP, Address senderFP, Address senderPC) {}; + private JavaNameInfo getJavaNames(JavaThread jthread, CFrame f) { List names = new ArrayList<>(10); - JavaVFrame bottomJVFrame = null; - for (int fCount = 0; fCount < jvframes.length; fCount++) { - JavaVFrame vf = jvframes[fCount]; - Frame f = vf.getFrame(); - if (fp.equals(f.getFP())) { - bottomJVFrame = vf; - StringBuilder sb = new StringBuilder(); - Method method = vf.getMethod(); - // a special char to identify java frames in output - sb.append("* "); - sb.append(method.externalNameAndSignature()); - sb.append(" bci:").append(vf.getBCI()); - int lineNumber = method.getLineNumberFromBCI(vf.getBCI()); - if (lineNumber != -1) { - sb.append(" line:").append(lineNumber); - } - - if (verbose) { - sb.append(" Method*:").append(method.getAddress()); - } - - if (vf.isCompiledFrame()) { - sb.append(" (Compiled frame"); - if (vf.isDeoptimized()) { - sb.append(" [deoptimized]"); - } - } else if (vf.isInterpretedFrame()) { - sb.append(" (Interpreted frame"); - } - if (vf.mayBeImpreciseDbg()) { - sb.append("; information may be imprecise"); - } - sb.append(")"); - names.add(sb.toString()); - } - } - + Address senderSP = null; Address senderFP = null; Address senderPC = null; - if (bottomJVFrame != null) { - Frame senderFrame = bottomJVFrame.getFrame().sender((RegisterMap)bottomJVFrame.getRegisterMap().clone()); + VFrame vf = VFrame.newVFrame(f.toFrame(), jthread.newRegisterMap(true), jthread, true, true); + while (vf != null && vf.isJavaFrame()) { + StringBuilder sb = new StringBuilder(); + Method method = ((JavaVFrame)vf).getMethod(); + // a special char to identify java frames in output + sb.append("* "); + sb.append(method.externalNameAndSignature()); + sb.append(" bci:").append(((JavaVFrame)vf).getBCI()); + int lineNumber = method.getLineNumberFromBCI(((JavaVFrame)vf).getBCI()); + if (lineNumber != -1) { + sb.append(" line:").append(lineNumber); + } + + if (verbose) { + sb.append(" Method*:").append(method.getAddress()); + } + + if (vf.isCompiledFrame()) { + sb.append(" (Compiled frame"); + if (vf.isDeoptimized()) { + sb.append(" [deoptimized]"); + } + } else if (vf.isInterpretedFrame()) { + sb.append(" (Interpreted frame"); + } + if (vf.mayBeImpreciseDbg()) { + sb.append("; information may be imprecise"); + } + sb.append(")"); + names.add(sb.toString()); + + // Keep registers in sender Frame + Frame senderFrame = vf.getFrame() + .sender((RegisterMap)vf.getRegisterMap().clone()); + senderSP = senderFrame.getSP(); senderFP = senderFrame.getFP(); senderPC = senderFrame.getPC(); + + // Get sender VFrame for next stack walking + vf = vf.sender(true); } - return new JavaNameInfo(names.toArray(new String[0]), senderFP, senderPC); + return new JavaNameInfo(names.toArray(new String[0]), senderSP, senderFP, senderPC); } public void setVerbose(boolean verbose) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U4Array.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U4Array.java new file mode 100644 index 00000000000..9836614d2c9 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/U4Array.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.utilities; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.TypeDataBase; +import sun.jvm.hotspot.types.WrongTypeException; +import sun.jvm.hotspot.utilities.Observable; +import sun.jvm.hotspot.utilities.Observer; + +public class U4Array extends GenericArray { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { + elemType = db.lookupType("u4"); + Type type = db.lookupType("Array"); + dataFieldOffset = type.getAddressField("_data").getOffset(); + } + + private static long dataFieldOffset; + protected static Type elemType; + + public U4Array(Address addr) { + super(addr, dataFieldOffset); + } + + public int at(int i) { + return (int)getIntegerAt(i); + } + + public Type getElemType() { + return elemType; + } +} diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java index 84535027eb4..7d11bd42c94 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -109,29 +109,69 @@ public class Headers implements Map> { } /** - * Normalize the key by converting to following form. - * First {@code char} upper case, rest lower case. - * key is presumed to be {@code ASCII}. + * {@return the normalized header name of the following form: the first + * character in upper-case, the rest in lower-case} + * The input header name is assumed to be encoded in ASCII. + * + * @implSpec + * This method is performance-sensitive; update with care. + * + * @param key an ASCII-encoded header name + * @throws NullPointerException on null {@code key} + * @throws IllegalArgumentException if {@code key} contains {@code \r} or {@code \n} */ - private String normalize(String key) { + private static String normalize(String key) { + + // Fast path for the empty key Objects.requireNonNull(key); - int len = key.length(); - if (len == 0) { + int l = key.length(); + if (l == 0) { return key; } - char[] b = key.toCharArray(); - if (b[0] >= 'a' && b[0] <= 'z') { - b[0] = (char)(b[0] - ('a' - 'A')); - } else if (b[0] == '\r' || b[0] == '\n') - throw new IllegalArgumentException("illegal character in key"); - for (int i=1; i= 'A' && b[i] <= 'Z') { - b[i] = (char) (b[i] + ('a' - 'A')); - } else if (b[i] == '\r' || b[i] == '\n') - throw new IllegalArgumentException("illegal character in key"); + // Find the first non-normalized `char` + int i = 0; + char c = key.charAt(i); + if (!(c == '\r' || c == '\n' || (c >= 'a' && c <= 'z'))) { + i++; + for (; i < l; i++) { + c = key.charAt(i); + if (c == '\r' || c == '\n' || (c >= 'A' && c <= 'Z')) { + break; + } + } } - return new String(b); + + // Fast path for the already normalized key + if (i == l) { + return key; + } + + // Upper-case the first `char` + char[] cs = key.toCharArray(); + int o = 'a' - 'A'; + if (i == 0) { + if (c == '\r' || c == '\n') { + throw new IllegalArgumentException("illegal character in key at index " + i); + } + if (c >= 'a' && c <= 'z') { + cs[0] = (char) (c - o); + } + i++; + } + + // Lower-case the secondary `char`s + for (; i < l; i++) { + c = cs[i]; + if (c >= 'A' && c <= 'Z') { + cs[i] = (char) (c + o); + } else if (c == '\r' || c == '\n') { + throw new IllegalArgumentException("illegal character in key at index " + i); + } + } + + return new String(cs); + } @Override diff --git a/src/jdk.internal.opt/share/classes/module-info.java b/src/jdk.internal.opt/share/classes/module-info.java index ba6987f1ea9..728c2de500d 100644 --- a/src/jdk.internal.opt/share/classes/module-info.java +++ b/src/jdk.internal.opt/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ module jdk.internal.opt { exports jdk.internal.joptsimple to jdk.jlink, jdk.jshell, + jdk.jpackage, jdk.jdeps; exports jdk.internal.opt to jdk.compiler, diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 46e53411dee..6074b2b32dc 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, 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 @@ -165,8 +165,12 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem } public int getAccessFlags() { - HotSpotVMConfig config = config(); - return UNSAFE.getInt(getKlassPointer() + config.klassAccessFlagsOffset); + if (isArray()) { + return 0; // Array Metadata doesn't set access_flags + } else { + HotSpotVMConfig config = config(); + return UNSAFE.getInt(getKlassPointer() + config.instanceKlassAccessFlagsOffset); + } } public int getMiscFlags() { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index e4e23c6d8b8..c058f785715 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -84,7 +84,6 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { */ final int javaMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle"); - final int klassAccessFlagsOffset = getFieldOffset("Klass::_access_flags", Integer.class, "AccessFlags"); final int klassLayoutHelperOffset = getFieldOffset("Klass::_layout_helper", Integer.class, "jint"); final int klassLayoutHelperNeutralValue = getConstant("Klass::_lh_neutral_value", Integer.class); @@ -93,6 +92,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { final int vtableEntrySize = getFieldValue("CompilerToVM::Data::sizeof_vtableEntry", Integer.class, "int"); final int vtableEntryMethodOffset = getFieldOffset("vtableEntry::_method", Integer.class, "Method*"); + final int instanceKlassAccessFlagsOffset = getFieldOffset("InstanceKlass::_access_flags", Integer.class, "AccessFlags"); final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "InstanceKlass::ClassState"); final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*"); final int instanceKlassFieldInfoStreamOffset = getFieldOffset("InstanceKlass::_fieldinfo_stream", Integer.class, "Array*"); diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java index f2c76058434..12967972a88 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java @@ -167,6 +167,7 @@ public class Main { char[] storepass; // keystore password boolean protectedPath; // protected authentication path String storetype; // keystore type + String realStoreType; String providerName; // provider name List providers = null; // list of provider names List providerClasses = null; // list of provider classes @@ -240,6 +241,7 @@ public class Main { private boolean signerSelfSigned = false; private boolean allAliasesFound = true; private boolean hasMultipleManifests = false; + private boolean weakKeyStore = false; private Throwable chainNotValidatedReason = null; private Throwable tsaChainNotValidatedReason = null; @@ -1482,6 +1484,12 @@ public class Main { warnings.add(rb.getString("external.file.attributes.detected")); } + if (weakKeyStore) { + warnings.add(String.format(rb.getString( + "jks.storetype.warning"), + realStoreType, keystore)); + } + if ((strict) && (!errors.isEmpty())) { result = isSigning ? rb.getString("jar.signed.with.signer.errors.") @@ -2422,6 +2430,23 @@ public class Main { is.close(); } } + + File storeFile = new File(keyStoreName); + if (storeFile.exists()) { + // Probe for real type. A JKS can be loaded as PKCS12 because + // DualFormat support, vice versa. + try { + KeyStore keyStore = KeyStore.getInstance(storeFile, storepass); + realStoreType = keyStore.getType(); + if (realStoreType.equalsIgnoreCase("JKS") + || realStoreType.equalsIgnoreCase("JCEKS")) { + weakKeyStore = true; + } + } catch (KeyStoreException e) { + // Probing not supported, therefore cannot be JKS or JCEKS. + // Skip the legacy type warning at all. + } + } } Enumeration aliases = store.aliases(); while (aliases.hasMoreElements()) { diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner.properties b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner.properties index b490d386e59..a16420daf8f 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner.properties +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/resources/jarsigner.properties @@ -222,3 +222,5 @@ entry.1.is.signed.in.jarinputstream.but.is.not.signed.in.jarfile=Entry %s is sig jar.contains.internal.inconsistencies.result.in.different.contents.via.jarfile.and.jarinputstream=This JAR file contains internal inconsistencies that may result in different contents when reading via JarFile and JarInputStream: signature.verification.failed.on.entry.1.when.reading.via.jarinputstream=Signature verification failed on entry %s when reading via JarInputStream signature.verification.failed.on.entry.1.when.reading.via.jarfile=Signature verification failed on entry %s when reading via JarFile +jks.storetype.warning=%1$s uses outdated cryptographic algorithms and will be removed in a future release. Migrate to PKCS12 using:\n\ +keytool -importkeystore -srckeystore %2$s -destkeystore %2$s -deststoretype pkcs12 diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java b/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java index 1852b2cad9d..be694eeb1bc 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java @@ -260,6 +260,19 @@ final class Validator { isValid = false; warn(getMsg("warn.validator.order.mismatch")); } + // Check location of an optional manifest entry + if ("META-INF/MANIFEST.MF".equals(entryName)) { + int index = entryInfo.cen().order(); + if (index > 1) { // Expect base manifest at index 0 or 1 + String position = Integer.toString(index); + errorAndInvalid(formatMsg("error.validator.manifest.wrong.position", position)); + } else if (index == 1) { // Ensure "META-INF/" preceeds manifest + String firstName = entries.sequencedKeySet().getFirst(); + if (!"META-INF/".equals(firstName)) { + errorAndInvalid(formatMsg("error.validator.metainf.wrong.position", firstName)); + } + } + } } /** diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties index 0e3555f181e..c80377e20c1 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties +++ b/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties @@ -134,6 +134,10 @@ error.validator.info.version.notequal=\ {0}: module-info.class in a versioned directory contains different "version" error.validator.info.manclass.notequal=\ {0}: module-info.class in a versioned directory contains different "main-class" +error.validator.metainf.wrong.position=\ + expected entry META-INF/ to be at position 0, but found: {0} +error.validator.manifest.wrong.position=\ + expected entry META-INF/MANIFEST.MF to be at position 0 or 1, but found it at position: {0} warn.validator.identical.entry=\ Warning: entry {0} contains a class that\n\ is identical to an entry already in the jar 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 6896b86279f..1f2c4d97dd3 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 @@ -908,12 +908,13 @@ public abstract class HtmlDocletWriter { * @param refMemName the name of the member being referenced. This should * be null or empty string if no member is being referenced. * @param label the label for the external link. + * @param title the title for the link * @param style optional style for the link. * @param code true if the label should be code font. * @return the link */ public Content getCrossClassLink(TypeElement classElement, String refMemName, - Content label, HtmlStyle style, boolean code) { + Content label, String title, HtmlStyle style, boolean code) { if (classElement != null) { String className = utils.getSimpleName(classElement); PackageElement packageElement = utils.containingPackage(classElement); @@ -931,9 +932,7 @@ public abstract class HtmlDocletWriter { DocLink link = configuration.extern.getExternalLink(packageElement, pathToRoot, className + ".html", refMemName); return links.createLink(link, - (label == null) || label.isEmpty() ? defaultLabel : label, style, - resources.getText("doclet.Href_Class_Or_Interface_Title", - getLocalizedPackageName(packageElement)), true); + (label == null) || label.isEmpty() ? defaultLabel : label, style, title, true); } } return null; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index 4dbbd5e172a..cb8b3dbfd40 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -305,7 +305,7 @@ public class HtmlLinkFactory { } else { Content crossLink = m_writer.getCrossClassLink( typeElement, linkInfo.getFragment(), - label, linkInfo.getStyle(), true); + label, linkInfo.getTitle(), linkInfo.getStyle(), true); if (crossLink != null) { link.add(crossLink); addSuperscript(link, flags, null, typeElement, previewTarget, restrictedTarget); @@ -361,7 +361,7 @@ public class HtmlLinkFactory { if (fileName != null) { return m_writer.links.createLink(fileName.fragment(id.name()), label); } else if (typeElement != null) { - return (m_writer.getCrossClassLink(typeElement, id.name(), label, null, false)); + return (m_writer.getCrossClassLink(typeElement, id.name(), label, null, null, false)); } else { return label; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java index 0af29135654..285ab260e0e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -197,7 +197,7 @@ public class Links { if (style != null) { l.setStyle(style); } - if (title != null && title.length() != 0) { + if (title != null && !title.isEmpty()) { l.put(HtmlAttr.TITLE, title); } if (isExternal) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index df3c2fc3a53..4366295477b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title=annotation interface in {0} doclet.Href_Enum_Title=enum in {0} doclet.Href_Enum_Class_Title=enum class in {0} doclet.Href_Type_Param_Title=type parameter in {0} -doclet.Href_Class_Or_Interface_Title=class or interface in {0} doclet.Summary=Summary: doclet.Detail=Detail: doclet.Module_Sub_Nav=Module: diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties index 2669aa9bdc0..4cbb4b97774 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_de.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title=Annotationsschnittstelle in {0} doclet.Href_Enum_Title=Enum in {0} doclet.Href_Enum_Class_Title=Enum-Klasse in {0} doclet.Href_Type_Param_Title=Typparameter in {0} -doclet.Href_Class_Or_Interface_Title=Klasse oder Schnittstelle in {0} doclet.Summary=Übersicht: doclet.Detail=Details: doclet.Module_Sub_Nav=Modul: diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_en.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_en.properties new file mode 100644 index 00000000000..e1312e77aa4 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_en.properties @@ -0,0 +1,28 @@ +# +# Copyright (c) 2025, 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. +# + +# Empty resource bundle to be used with English default bundle as parent. +# This is necessary to make English resources available on systems using +# one of the supported non-English locales as default locale. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties index 1694dc980bc..2151b3f4a2e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_ja.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title={0}内の注釈インタフェース doclet.Href_Enum_Title={0}内の列挙型 doclet.Href_Enum_Class_Title={0}の列挙クラス doclet.Href_Type_Param_Title={0}内の型パラメータ -doclet.Href_Class_Or_Interface_Title={0}内のクラスまたはインタフェース doclet.Summary=概要: doclet.Detail=詳細: doclet.Module_Sub_Nav=モジュール: diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties index 8881171351e..66620d158bb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_zh_CN.properties @@ -51,7 +51,6 @@ doclet.Href_Annotation_Interface_Title={0} 中的批注接口 doclet.Href_Enum_Title={0}中的枚举 doclet.Href_Enum_Class_Title={0} 中的枚举类 doclet.Href_Type_Param_Title={0}中的类型参数 -doclet.Href_Class_Or_Interface_Title={0}中的类或接口 doclet.Summary=概要: doclet.Detail=详细资料: doclet.Module_Sub_Nav=模块: diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java index 914f70ced47..62b003afd96 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java @@ -50,6 +50,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlId; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -159,6 +160,10 @@ public class LinkTaglet extends BaseTaglet { Optional.of(refSignature)); } refFragment = refFragment.substring(1); + if (ref == null && refSignature.startsWith("##")) { + // Unqualified local anchor link in doc-file + return htmlWriter.links.createLink(HtmlId.of(refFragment), labelContent); + } } if (refClass == null) { ModuleElement refModule = ch.getReferencedModule(ref); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java index d16c47dd59f..38baa7b2826 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java @@ -162,10 +162,11 @@ public class SnippetTaglet extends BaseTaglet { case Style.Markup m -> markupEncountered = true; } } - Content c; if (markupEncountered) { return; - } else if (linkTarget != null) { + } + Content c = Text.of(text); + if (linkTarget != null) { //disable preview tagging inside the snippets: Utils.PreviewFlagProvider prevPreviewProvider = utils.setPreviewFlagProvider(el -> false); try { @@ -174,15 +175,16 @@ public class SnippetTaglet extends BaseTaglet { null, linkTarget, ref, - false, // TODO: for now + true, Text.of(sequence.toString()), (key, args) -> { /* Error has already been reported above */ }, tagletWriter); } finally { utils.setPreviewFlagProvider(prevPreviewProvider); } - } else { - c = HtmlTree.SPAN(Text.of(text)); + } + if (!classes.isEmpty()) { + c = HtmlTree.SPAN(c); classes.forEach(((HtmlTree) c)::addStyle); } code.add(c); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_en.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_en.properties new file mode 100644 index 00000000000..e1312e77aa4 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_en.properties @@ -0,0 +1,28 @@ +# +# Copyright (c) 2025, 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. +# + +# Empty resource bundle to be used with English default bundle as parent. +# This is necessary to make English resources available on systems using +# one of the supported non-English locales as default locale. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index 3669c800a8e..43405c3ebb0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -1004,12 +1004,15 @@ public class Checker extends DocTreePathScanner { @Override @DefinedBy(Api.COMPILER_TREE) public Void visitReference(ReferenceTree tree, Void ignore) { - Element e = env.trees.getElement(getCurrentPath()); - if (e == null) { - reportBadReference(tree); - } else if ((inLink || inSee) - && e.getKind() == ElementKind.CLASS && e.asType().getKind() != TypeKind.DECLARED) { - reportBadReference(tree); + // Exclude same-file anchor links from reference checks + if (!tree.getSignature().startsWith("##")) { + Element e = env.trees.getElement(getCurrentPath()); + if (e == null) { + reportBadReference(tree); + } else if ((inLink || inSee) + && e.getKind() == ElementKind.CLASS && e.asType().getKind() != TypeKind.DECLARED) { + reportBadReference(tree); + } } return super.visitReference(tree, ignore); } diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java index 19e8b45c491..9a13eb3dca5 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -37,6 +37,7 @@ import com.sun.jdi.InternalException; import com.sun.jdi.Locatable; import com.sun.jdi.Location; import com.sun.jdi.Method; +import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.ObjectReference; import com.sun.jdi.ReferenceType; import com.sun.jdi.ThreadReference; @@ -206,6 +207,19 @@ public class EventSetImpl extends ArrayList implements EventSet { } + /* Safely fetch the thread name in case there is an ObjectCollectedException. + * This can happen when dealing with SUSPEND_NONE events. + */ + private static String getThreadName(ThreadReference thread) { + String name; + try { + name = thread.name(); + } catch (ObjectCollectedException oce) { + name = ""; + } + return name; + } + abstract class ThreadedEventImpl extends EventImpl { private ThreadReference thread; @@ -220,7 +234,7 @@ public class EventSetImpl extends ArrayList implements EventSet { } public String toString() { - return eventName() + " in thread " + thread.name(); + return eventName() + " in thread " + getThreadName(thread); } } @@ -249,7 +263,7 @@ public class EventSetImpl extends ArrayList implements EventSet { public String toString() { return eventName() + "@" + ((location() == null) ? " null" : location().toString()) + - " in thread " + thread().name(); + " in thread " + getThreadName(thread()); } } diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index bfeffe85678..8a02f3f9ee9 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -70,6 +70,7 @@ typedef struct ThreadNode { unsigned int popFrameEvent : 1; unsigned int popFrameProceed : 1; unsigned int popFrameThread : 1; + unsigned int frameGeneration_accessed:1; /* true if frameGeneration accessed to produce a FrameID */ EventIndex current_ei; /* Used to determine if we are currently handling an event on this thread. */ jobject pendingStop; /* Object we are throwing to stop the thread (ThreadReferenceImpl.stop). */ jint suspendCount; /* Number of outstanding suspends from the debugger. */ @@ -137,6 +138,9 @@ typedef struct { static DeferredEventModeList deferredEventModes; +static ThreadNode * +insertThread(JNIEnv *env, ThreadList *list, jthread thread); + /* Get the state of the thread direct from JVMTI */ static jvmtiError threadState(jthread thread, jint *pstate) @@ -154,11 +158,24 @@ setThreadLocalStorage(jthread thread, ThreadNode *node) error = JVMTI_FUNC_PTR(gdata->jvmti,SetThreadLocalStorage) (gdata->jvmti, thread, (void*)node); - if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE && node == NULL) { - /* Just return. This can happen when clearing the TLS. */ + if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) { + if (node == NULL) { + // Just return. This can happen when clearing the TLS. + return; + } + if (isVThread(thread)) { + // Just return. This can happen with a vthread that is running and we + // had to create a ThreadNode for it. By the time we get here, it may + // have already terminated. + return; + } + } + if (error == JVMTI_ERROR_WRONG_PHASE && gdata->vmDead && isVThread(thread)) { + // Just return. This can happen with vthreads when the vm is exiting. return; - } else if ( error != JVMTI_ERROR_NONE ) { - /* The jthread object must be valid, so this must be a fatal error */ + } + if (error != JVMTI_ERROR_NONE) { + // The jthread object must be valid, so this must be a fatal error. EXIT_ERROR(error, "cannot set thread local storage"); } } @@ -248,9 +265,10 @@ findThread(ThreadList *list, jthread thread) * Otherwise the thread should not be on the runningThreads. */ if ( !gdata->jvmtiCallBacksCleared ) { - /* The thread better not be on either list if the TLS lookup failed. */ + // The thread better not be on the runningThreads list if the TLS lookup failed. + // It might be on the runningVThreads list because of how ThreadNodes for vthreads + // can be recreated just before terminating, so we don't check runningVThreads. JDI_ASSERT(!nonTlsSearch(getEnv(), &runningThreads, thread)); - JDI_ASSERT(!nonTlsSearch(getEnv(), &runningVThreads, thread)); } else { /* * Search the runningThreads and runningVThreads lists. The TLS lookup may have @@ -277,6 +295,35 @@ findThread(ThreadList *list, jthread thread) return node; } +/* Creates a new ThreadNode for a vthread if one is needed. */ +static ThreadNode * +createVThreadNodeIfNeeded(jthread thread) { + ThreadNode *node = findThread(&otherThreads, thread); + if (node != NULL) { + //tty_message("createVThreadNodeIfNeeded: thread is on otherThreads"); + // Don't create a new node if it is on otherThreads list. Also don't return + // the existing node because if it is on otherThreads, it is not running. + return NULL; + } + + // See if we have a vthread that is alive. If we do, create a ThreadNode + // for it. Otherwise just return NULL. + jint vthread_state = 0; + jvmtiError error = threadState(thread, &vthread_state); + if (error != JVMTI_ERROR_NONE) { + EXIT_ERROR(error, "getting vthread state"); + } + if ((vthread_state & JVMTI_THREAD_STATE_ALIVE) == 0) { + return NULL; // Don't create a new ThreadNode if thread is not alive + } + node = insertThread(getEnv(), &runningVThreads, thread); + if (node->suspendCount > 0 && !node->suspendOnStart) { + node->toBeResumed = JNI_TRUE; + } + + return node; +} + /* Search for a running thread, including vthreads. */ static ThreadNode * findRunningThread(jthread thread) @@ -284,6 +331,16 @@ findRunningThread(jthread thread) ThreadNode *node; if (isVThread(thread)) { node = findThread(&runningVThreads, thread); + if (node == NULL && !gdata->includeVThreads) { + // Unlike platform threads, we don't always have a ThreadNode for all vthreads. + // They can be freed if not holding on to any relevant state info. It's also + // possible that the vthread was created before the debugger attached. Also + // in the future we won't be enabling VIRTUAL_THREAD_START events in some + // cases, which means we won't be creating a ThreadNode when the vthread is + // created. If for any of the above reasons the ThreadNode lookup failed, + // we'll create one for the vthread now, but only if really needed. + node = createVThreadNodeIfNeeded(thread); + } } else { node = findThread(&runningThreads, thread); } @@ -370,6 +427,23 @@ insertThread(JNIEnv *env, ThreadList *list, jthread thread) EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry"); return NULL; } + +#ifdef DEBUG_THREADNAME + { + /* Set the thread name */ + jvmtiThreadInfo info; + jvmtiError error; + + memset(&info, 0, sizeof(info)); + error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) + (gdata->jvmti, node->thread, &info); + if (info.name != NULL) { + strncpy(node->name, info.name, sizeof(node->name) - 1); + jvmtiDeallocate(info.name); + } + } +#endif + if (!is_vthread) { if (threadControl_isDebugThread(node->thread)) { /* Remember if it is a debug thread */ @@ -418,22 +492,6 @@ insertThread(JNIEnv *env, ThreadList *list, jthread thread) node->eventBag = eventBag; addNode(list, node); -#ifdef DEBUG_THREADNAME - { - /* Set the thread name */ - jvmtiThreadInfo info; - jvmtiError error; - - memset(&info, 0, sizeof(info)); - error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) - (gdata->jvmti, node->thread, &info); - if (info.name != NULL) { - strncpy(node->name, info.name, sizeof(node->name) - 1); - jvmtiDeallocate(info.name); - } - } -#endif - /* Set thread local storage for quick thread -> node access. * Threads that are not yet started do not allow setting of TLS. These * threads go on the otherThreads list and have their TLS set @@ -491,8 +549,7 @@ removeResumed(JNIEnv *env, ThreadList *list) static void removeVThreads(JNIEnv *env) { - ThreadList *list = &runningVThreads; - ThreadNode *node = list->first; + ThreadNode *node = runningVThreads.first; while (node != NULL) { ThreadNode *temp = node->next; removeNode(node); @@ -501,6 +558,95 @@ removeVThreads(JNIEnv *env) } } +/* + * Free (garbage collect) a vthread node if it is unused. This can only be called when + * locks are held so we don't need to worry about other threads changing the state + * of the ThreadNode while we are looking at it. We also need to make sure the + * ThreadNode is not in use for operations like single stepping or invoking. + */ +static void +freeUnusedVThreadNode(JNIEnv *env, ThreadNode* node) +{ + if (gdata->includeVThreads) { + return; + } + + /* + * node->suspendCount requires special handling to see if it triggers having + * to keep the node around. It's possible for it to be 0 yet we still need to + * keep the node around. Also, it's possbile for it to be non-zero yet we + * don't need to keep the node around. More details in the comments below. + */ + if (node->suspendCount == 0) { + /* + * Normally a suspendCount of 0 does not result in having to keep the + * node. However, if the suspendAllCount is not 0, then we do. Otherwise + * when the node is recreated later it will end up assuming suspendAllCount + * as its suspendCount rather than 0, which would be incorrect. This + * mismatch in suspend counts happens when there is a suspendAll in place, + * and ThreadReference.resume() is used to decrement the thread's + * suspendCount to 0. + */ + if (suspendAllCount > 0) { + return; + } + } else { + /* + * Although at first it might seem that a non-zero suspendCount would require + * keeping the node, we don't have to if node->suspendCount == suspendAllCount, + * because when the node is recreated it will get suspendAllCount assigned to it. + * So we only worry about keeping the node around if the two counts are not equal. + */ + if (node->suspendCount != suspendAllCount) { + return; + } + + } + + // All of the following conditions must be met to free this node. Note + // suspendCount checks were already made above, so are not included below. If + // we got here, then suspendCount checks passed w.r.t. being able to free the node. + // Also note we don't need to check node->toBeResumed. If it is set, that implies + // node->suspendCount > 0, and that will trigger toBeResumed getting set when + // the ThreadNode is recreated. See createVThreadNodeIfNeeded(). + if (!node->suspendOnStart && + node->current_ei == 0 && + node->cleInfo.ei == 0 && + !node->currentInvoke.pending && + !node->currentInvoke.started && + !node->currentInvoke.available && + !node->currentStep.pending && + node->instructionStepMode != JVMTI_ENABLE && + !node->pendingInterrupt && + !node->popFrameEvent && + !node->popFrameProceed && + !node->popFrameThread && + !node->frameGeneration_accessed && + node->pendingStop == NULL) + { + removeNode(node); + clearThread(env, node); + } +} + +/* + * Free (garbage collect) vthread nodes if unused. See freeUnusedVThreadNode() above. + */ +static void +freeUnusedVThreadNodes(JNIEnv *env) +{ + if (gdata->includeVThreads) { + return; + } + + ThreadNode *node = runningVThreads.first; + while (node != NULL) { + ThreadNode *temp = node->next; + freeUnusedVThreadNode(env, node); + node = temp; + } +} + static void moveNode(ThreadList *source, ThreadList *dest, ThreadNode *node) { @@ -1139,6 +1285,7 @@ commonResumeList(JNIEnv *env) /* * This function must be called after preSuspend and before postSuspend. + * Only called for platform threads. */ static jvmtiError commonSuspendList(JNIEnv *env, jint initCount, jthread *initList) @@ -1160,15 +1307,17 @@ commonSuspendList(JNIEnv *env, jint initCount, jthread *initList) */ for (i = 0; i < initCount; i++) { ThreadNode *node; + jthread thread = initList[i]; + JDI_ASSERT(!isVThread(thread)); /* * If the thread is not between its start and end events, we should * still suspend it. To keep track of things, add the thread * to a separate list of threads so that we'll resume it later. */ - node = findThread(&runningThreads, initList[i]); + node = findThread(&runningThreads, thread); if (node == NULL) { - node = insertThread(env, &otherThreads, initList[i]); + node = insertThread(env, &otherThreads, thread); } if (node->isDebugThread) { @@ -1187,7 +1336,7 @@ commonSuspendList(JNIEnv *env, jint initCount, jthread *initList) if (node->suspendCount == 0) { /* thread is not suspended yet so put it on the request list */ - reqList[reqCnt++] = initList[i]; + reqList[reqCnt++] = thread; } } @@ -1255,10 +1404,16 @@ commonResume(jthread thread) ThreadNode *node; /* - * The thread is normally between its start and end events, but if - * not, check the auxiliary list used by threadControl_suspendThread. + * We need to call findRunningThread(thread) here instead of just calling + * findThread(NULL, thread) because it's possible that there is not currently a + * ThreadNode for the thread, and findRunningThread() will create one in that case. */ - node = findThread(NULL, thread); + node = findRunningThread(thread); + if (node == NULL) { + // The thread is normally between its start and end events, but if not, + // check the auxiliary list used by commonSuspend() and commonSuspendList(). + node = findThread(&otherThreads, thread); + } #if 0 tty_message("commonResume: node(%p) suspendCount(%d) %s", node, node->suspendCount, node->name); #endif @@ -1336,24 +1491,9 @@ threadControl_suspendCount(jthread thread, jint *count) } else { /* * If the node is in neither list, the debugger never suspended - * this thread, so the suspend count is 0, unless it is a vthread. + * this thread, so the suspend count is 0. */ - if (isVThread(thread)) { - jint vthread_state = 0; - jvmtiError error = threadState(thread, &vthread_state); - if (error != JVMTI_ERROR_NONE) { - EXIT_ERROR(error, "getting vthread state"); - } - if (vthread_state == 0) { - // If state == 0, then this is a new vthread that has not been started yet. - *count = 0; - } else { - // This is a started vthread that we are not tracking. Use suspendAllCount. - *count = suspendAllCount; - } - } else { - *count = 0; - } + *count = 0; } debugMonitorExit(threadLock); @@ -1406,9 +1546,6 @@ threadControl_suspendAll(void) { jvmtiError error; JNIEnv *env; -#if 0 - tty_message("threadControl_suspendAll: suspendAllCount(%d)", suspendAllCount); -#endif env = getEnv(); @@ -1416,6 +1553,8 @@ threadControl_suspendAll(void) preSuspend(); + //tty_message("threadControl_suspendAll: suspendAllCount(%d)", suspendAllCount); + /* * Get a list of all threads and suspend them. */ @@ -1425,6 +1564,11 @@ threadControl_suspendAll(void) jint count; if (gdata->vthreadsSupported) { + // Now is a good time to garbage collect vthread nodes. We want to do it before + // any suspendAll because it will prevent the suspended nodes from being freed. + if (!gdata->includeVThreads) { + freeUnusedVThreadNodes(env); + } /* Tell JVMTI to suspend all virtual threads. */ if (suspendAllCount == 0) { error = JVMTI_FUNC_PTR(gdata->jvmti, SuspendAllVirtualThreads) @@ -1528,9 +1672,6 @@ threadControl_resumeAll(void) { jvmtiError error; JNIEnv *env; -#if 0 - tty_message("threadControl_resumeAll: suspendAllCount(%d)", suspendAllCount); -#endif env = getEnv(); @@ -1539,6 +1680,8 @@ threadControl_resumeAll(void) eventHandler_lock(); /* for proper lock order */ debugMonitorEnter(threadLock); + //tty_message("threadControl_resumeAll: suspendAllCount(%d)", suspendAllCount); + if (gdata->vthreadsSupported) { if (suspendAllCount == 1) { jint excludeCnt = 0; @@ -2092,7 +2235,7 @@ threadControl_onEventHandlerEntry(jbyte sessionID, EventInfo *evinfo, jobject cu processDeferredEventModes(env, thread, node); } if (ei == EI_THREAD_END) { - // If the node was previously freed, then it was just recreated and we need + // If the node was previously freed and was just now recreated, we need // to mark it as started. node->isStarted = JNI_TRUE; } @@ -2148,17 +2291,30 @@ threadControl_onEventHandlerExit(EventIndex ei, jthread thread, log_debugee_location("threadControl_onEventHandlerExit()", thread, NULL, 0); - if (ei == EI_THREAD_END) { + if (ei == EI_THREAD_END || ei == EI_THREAD_START) { eventHandler_lock(); /* for proper lock order - see removeThread() call below */ debugMonitorEnter(threadLock); node = findRunningThread(thread); if (node == NULL) { EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted"); } - removeThread(env, node); // Grabs handlerLock, thus the reason for first grabbing it above. - node = NULL; // We exiting the threadLock. No longer safe to access. - debugMonitorExit(threadLock); - eventHandler_unlock(); + // Remove nodes for exiting threads, but also remove nodes for vthreads + // that are just starting to help prevent their accumulation. There can't + // possibly be any state related information in the node at this point. A new + // one will be created later if necessary, such as when a new event arrives. + if (ei == EI_THREAD_END || (node->is_vthread && !gdata->includeVThreads)) { + removeThread(env, node); // Grabs handlerLock, thus the reason for first grabbing it above. + node = NULL; // Node has been freed. No longer safe to access. + } else { + // EI_THREAD_START for a platform thread, or we are tracking vthreads. + // In either case we are not removing the thread node. + // Just clear these two fields. Others are not set yet. Also no need to + // worry about pending tasks like we do below for other event types. + node->eventBag = eventBag; + node->current_ei = 0; + } + debugMonitorExit(threadLock); + eventHandler_unlock(); } else { debugMonitorEnter(threadLock); node = findRunningThread(thread); @@ -2173,7 +2329,7 @@ threadControl_onEventHandlerExit(EventIndex ei, jthread thread, node->pendingStop = NULL; node->eventBag = eventBag; node->current_ei = 0; - node = NULL; // We exiting the threadLock. No longer safe to access. + node = NULL; // We're exiting the threadLock. No longer safe to access. // doPendingTasks() may do an upcall to java, and we don't want to hold any // locks when doing that. Thus we got all our node updates done first // and can now exit the threadLock. @@ -2189,6 +2345,8 @@ threadControl_onEventHandlerExit(EventIndex ei, jthread thread, // until now. Otherwise there are complaints when JNI IsVirtualThread is called. JNI_FUNC_PTR(env,Throw)(env, currentException); } + // Note: Threads that were just created or are about to die don't have pending + // tasks, which is why this is the only code path where we call doPendingTasks(). doPendingTasks(env, thread, pendingInterrupt, pendingStop); if (pendingStop != NULL) { tossGlobalRef(env, &pendingStop); @@ -2207,6 +2365,7 @@ threadControl_applicationThreadStatus(jthread thread, log_debugee_location("threadControl_applicationThreadStatus()", thread, NULL, 0); + eventHandler_lock(); // Needed to safely access HANDLING_EVENT(node) debugMonitorEnter(threadLock); error = threadState(thread, &state); @@ -2229,6 +2388,7 @@ threadControl_applicationThreadStatus(jthread thread, } debugMonitorExit(threadLock); + eventHandler_unlock(); return error; } @@ -2334,6 +2494,7 @@ threadControl_stop(jthread thread, jobject throwable) log_debugee_location("threadControl_stop()", thread, NULL, 0); + eventHandler_lock(); // Needed to safely access HANDLING_EVENT(node) debugMonitorEnter(threadLock); node = findThread(&runningThreads, thread); @@ -2351,6 +2512,7 @@ threadControl_stop(jthread thread, jobject throwable) } debugMonitorExit(threadLock); + eventHandler_unlock(); return error; } @@ -2527,6 +2689,7 @@ threadControl_getFrameGeneration(jthread thread) if (node != NULL) { frameGeneration = node->frameGeneration; + node->frameGeneration_accessed = JNI_TRUE; } } debugMonitorExit(threadLock); @@ -2579,7 +2742,7 @@ threadControl_dumpAllThreads() tty_message("suspendAllCount: %d", suspendAllCount); tty_message("Dumping runningThreads:"); dumpThreadList(&runningThreads); - tty_message("\nDumping runningVThreads:"); + tty_message("\nDumping runningVThreads(numRunningVThreads=%d):", numRunningVThreads); dumpThreadList(&runningVThreads); tty_message("\nDumping otherThreads:"); dumpThreadList(&otherThreads); @@ -2650,9 +2813,11 @@ dumpThread(ThreadNode *node) { // kept small so it doesn't generate too much output. tty_message("\tsuspendCount: %d", node->suspendCount); #if 0 + tty_message("\ttoBeResumed: %d", node->toBeResumed); + tty_message("\tisStarted: %d", node->isStarted); + tty_message("\tsuspendOnStart: %d", node->suspendOnStart); tty_message("\tsuspendAllCount: %d", suspendAllCount); tty_message("\tthreadState: 0x%x", getThreadState(node)); - tty_message("\ttoBeResumed: %d", node->toBeResumed); tty_message("\tis_vthread: %d", node->is_vthread); tty_message("\tpendingInterrupt: %d", node->pendingInterrupt); tty_message("\tcurrentInvoke.pending: %d", node->currentInvoke.pending); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/FinalFieldMutationEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/FinalFieldMutationEvent.java new file mode 100644 index 00000000000..8f90ad2c8fd --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/FinalFieldMutationEvent.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, 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 jdk.jfr.events; + +import jdk.jfr.Category; +import jdk.jfr.Description; +import jdk.jfr.Label; +import jdk.jfr.Name; +import jdk.jfr.internal.Type; +import jdk.jfr.internal.MirrorEvent; +import jdk.jfr.internal.RemoveFields; + +@Category("Java Application") +@Label("Final Field Mutation") +@Name(Type.EVENT_NAME_PREFIX + "FinalFieldMutation") +@RemoveFields("duration") +@StackFilter({ + "java.lang.reflect.Field", + "java.lang.reflect.ReflectAccess", + "java.lang.invoke.MethodHandles$Lookup" +}) +public final class FinalFieldMutationEvent extends MirrorEvent { + + @Label("Declaring Class") + @Description("Declaring class with final field") + public Class declaringClass; + + @Label("Field Name") + @Description("Field name of final field") + public String fieldName; + +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java index 503a7955e00..53d40c1e5e1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java @@ -76,6 +76,7 @@ public final class JDKEvents { jdk.internal.event.VirtualThreadSubmitFailedEvent.class, jdk.internal.event.X509CertificateEvent.class, jdk.internal.event.X509ValidationEvent.class, + jdk.internal.event.FinalFieldMutationEvent.class, DirectBufferStatisticsEvent.class, InitialSecurityPropertyEvent.class, MethodTraceEvent.class, diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java index 48dc0d22cea..7cbd893ee1d 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, 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 jdk.jfr.events.ExceptionThrownEvent; import jdk.jfr.events.FileForceEvent; import jdk.jfr.events.FileReadEvent; import jdk.jfr.events.FileWriteEvent; +import jdk.jfr.events.FinalFieldMutationEvent; import jdk.jfr.events.ProcessStartEvent; import jdk.jfr.events.SecurityPropertyModificationEvent; import jdk.jfr.events.SecurityProviderServiceEvent; @@ -77,6 +78,7 @@ final class MirrorEvents { register("jdk.internal.event.ErrorThrownEvent", ErrorThrownEvent.class); register("jdk.internal.event.ExceptionStatisticsEvent", ExceptionStatisticsEvent.class); register("jdk.internal.event.ExceptionThrownEvent", ExceptionThrownEvent.class); + register("jdk.internal.event.FinalFieldMutationEvent", FinalFieldMutationEvent.class); }; private static void register(String eventClassName, Class mirrorClass) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java index 30bd96ba86a..1180ebd6ea2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java @@ -34,6 +34,7 @@ import jdk.jfr.internal.periodic.PeriodicEvents; import jdk.jfr.internal.util.ImplicitFields; import jdk.jfr.internal.util.TimespanRate; import jdk.jfr.internal.util.Utils; +import jdk.jfr.internal.settings.CPUThrottleSetting; import jdk.jfr.internal.settings.Throttler; import jdk.jfr.internal.tracing.Modification; @@ -60,7 +61,7 @@ public final class PlatformEventType extends Type { private boolean stackTraceEnabled = true; private long thresholdTicks = 0; private long period = 0; - private TimespanRate cpuRate; + private TimespanRate cpuRate = TimespanRate.of(CPUThrottleSetting.DEFAULT_VALUE); private boolean hasHook; private boolean beginChunk; @@ -125,6 +126,7 @@ public final class PlatformEventType extends Type { Type.EVENT_NAME_PREFIX + "FileWrite" -> 6; case Type.EVENT_NAME_PREFIX + "FileRead", Type.EVENT_NAME_PREFIX + "FileForce" -> 5; + case Type.EVENT_NAME_PREFIX + "FinalFieldMutation" -> 4; default -> 3; }; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java index b07a71dd4d5..64454fc3cb4 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java @@ -34,6 +34,7 @@ import static jdk.jfr.internal.LogTag.JFR; import java.io.IOException; import java.io.InputStream; import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.StandardOpenOption; @@ -744,7 +745,14 @@ public final class PlatformRecording implements AutoCloseable { } private void transferChunks(WriteablePath path) throws IOException { - try (ChunksChannel cc = new ChunksChannel(chunks); FileChannel fc = FileChannel.open(path.getReal(), StandardOpenOption.WRITE, StandardOpenOption.APPEND)) { + // Before writing, wipe the file if it already exists. + try (ChunksChannel cc = new ChunksChannel(chunks); FileChannel fc = FileChannel.open(path.getReal(), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) { + // Mitigate races against other processes + FileLock l = fc.tryLock(); + if (l == null) { + Logger.log(LogTag.JFR, LogLevel.INFO, "Dump operation skipped for recording \"" + name + "\" (" + id + "). File " + path.getRealPathText() + " is locked by other dump operation or activity."); + return; + } long bytes = cc.transferTo(fc); Logger.log(LogTag.JFR, LogLevel.INFO, "Transferred " + bytes + " bytes from the disk repository"); // No need to force if no data was transferred, which avoids IOException when device is /dev/null diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini index 91decb1aa20..5d72a9f85dc 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini @@ -110,6 +110,15 @@ table = "COLUMN 'Time', 'Requested By', 'Operation', 'Classes' GROUP BY redefinitionId ORDER BY duration DESC" +[jvm.classes-by-source] + label = "Classes by Source" + table = "COLUMN 'Source', 'Count' + FORMAT truncate-beginning, none + SELECT source, COUNT(*) AS C + FROM jdk.ClassDefine + GROUP BY source + ORDER BY C DESC" + [jvm.compiler-configuration] label = "Compiler Configuration" form = "SELECT LAST(threadCount), LAST(dynamicCompilerThreadCount), LAST(tieredCompilation) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java index 944827f6d6f..7ea0ace21bb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java @@ -65,7 +65,7 @@ public final class CPUThrottleSetting extends SettingControl { } } } - return Objects.requireNonNullElse(highestRate.toString(), DEFAULT_VALUE); + return highestRate == null ? DEFAULT_VALUE : highestRate.toString(); } @Override diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java index 2632cd63848..0a7b14965cb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,7 +34,7 @@ public record Rate(long amount, TimespanUnit unit) { String value = splitted[0].strip(); String unit = splitted[1].strip(); TimespanUnit tu = TimespanUnit.fromText(unit); - if (unit == null) { + if (tu == null) { return null; } try { diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index eb3b8626722..554e09261d6 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -117,6 +117,11 @@ everyChunk + + true + true + + true true @@ -486,6 +491,11 @@ true + + true + 0 ms + + true diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 5ffdc8d9e4d..108886fb18d 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -117,6 +117,11 @@ everyChunk + + true + true + + true true @@ -486,6 +491,11 @@ true + + true + 0 ms + + true diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index 928b9a47934..03b9611c179 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -27,9 +27,11 @@ package jdk.tools.jlink.internal; import static jdk.tools.jlink.internal.TaskHelper.JLINK_BUNDLE; import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.UncheckedIOException; import java.lang.module.Configuration; @@ -56,6 +58,7 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -238,6 +241,27 @@ public class JlinkTask { } public static final String OPTIONS_RESOURCE = "jdk/tools/jlink/internal/options"; + // Release information stored in the java.base module + private static final String JDK_RELEASE_RESOURCE = "jdk/internal/misc/resources/release.txt"; + + /** + * Read the release.txt from the module. + */ + private static Optional getReleaseInfo(ModuleReference mref) { + try { + Optional release = mref.open().open(JDK_RELEASE_RESOURCE); + + if (release.isEmpty()) { + return Optional.empty(); + } + + try (var r = new BufferedReader(new InputStreamReader(release.get()))) { + return Optional.of(r.readLine()); + } + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } int run(String[] args) { if (log == null) { @@ -410,7 +434,8 @@ public class JlinkTask { // Sanity check version if we use JMODs if (!isLinkFromRuntime) { - checkJavaBaseVersion(finder); + assert(finder.find("java.base").isPresent()); + checkJavaBaseVersion(finder.find("java.base").get()); } // Determine the roots set @@ -561,32 +586,34 @@ public class JlinkTask { return finder; } + private static String getCurrentRuntimeVersion() { + ModuleReference current = ModuleLayer.boot() + .configuration() + .findModule("java.base") + .get() + .reference(); + // This jlink runtime should always have the release.txt + return getReleaseInfo(current).get(); + } + /* - * Checks the version of the module descriptor of java.base for compatibility - * with the current runtime version. + * Checks the release information of the java.base used for target image + * for compatibility with the java.base used by jlink. * - * @throws IllegalArgumentException the descriptor of java.base has no - * version or the java.base version is not the same as the current runtime's - * version. + * @throws IllegalArgumentException If the `java.base` module reference `target` + * is not compatible with this jlink. */ - private static void checkJavaBaseVersion(ModuleFinder finder) { - assert finder.find("java.base").isPresent(); + private static void checkJavaBaseVersion(ModuleReference target) { + String currentRelease = getCurrentRuntimeVersion(); - // use the version of java.base module, if present, as - // the release version for multi-release JAR files - ModuleDescriptor.Version v = finder.find("java.base").get() - .descriptor().version().orElseThrow(() -> - new IllegalArgumentException("No version in java.base descriptor") - ); + String targetRelease = getReleaseInfo(target).orElseThrow(() -> new IllegalArgumentException( + taskHelper.getMessage("err.jlink.version.missing", currentRelease))); - Runtime.Version version = Runtime.Version.parse(v.toString()); - if (Runtime.version().feature() != version.feature() || - Runtime.version().interim() != version.interim()) { - // jlink version and java.base version do not match. - // We do not (yet) support this mode. + if (!currentRelease.equals(targetRelease)) { + // Current runtime image and the target runtime image are not compatible build throw new IllegalArgumentException(taskHelper.getMessage("err.jlink.version.mismatch", - Runtime.version().feature(), Runtime.version().interim(), - version.feature(), version.interim())); + currentRelease, + targetRelease)); } } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java index d53589dc388..dca4d57f764 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java @@ -362,10 +362,13 @@ public final class TaskHelper { if (plugin instanceof DefaultCompressPlugin) { plugOption - = new PluginOption(false, + = new PluginOption(true, (task, opt, arg) -> { Map m = addArgumentMap(plugin); - m.put(plugin.getName(), DefaultCompressPlugin.LEVEL_2); + String level = (arg != null && !arg.isEmpty()) + ? arg + :"zip-6"; + m.put(plugin.getName(), level); }, false, "--compress", "-c"); mainOptions.add(plugOption); } else if (plugin instanceof DefaultStripDebugPlugin) { diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java index b4301ea8e45..25789b4d172 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, 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,11 +25,13 @@ package jdk.tools.jlink.internal.plugins; import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; import java.io.IOException; import java.io.PrintWriter; +import java.io.Reader; import java.io.UncheckedIOException; import java.lang.module.ModuleDescriptor; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; @@ -107,8 +109,8 @@ public final class ReleaseInfoPlugin extends AbstractPlugin { default: { // --release-info Properties props = new Properties(); - try (FileInputStream fis = new FileInputStream(operation)) { - props.load(fis); + try (Reader reader = Files.newBufferedReader(Path.of(operation))) { + props.load(reader); // Use reader API so as to read in as UTF-8 } catch (IOException exp) { throw new UncheckedIOException(exp); } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties index 080d51506a6..374ed78f608 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties @@ -130,7 +130,9 @@ err.runtime.link.patched.module=jlink does not support linking from the run-time err.no.module.path=--module-path option must be specified with --add-modules ALL-MODULE-PATH err.empty.module.path=No module found in module path ''{0}'' with --add-modules ALL-MODULE-PATH err.limit.modules=--limit-modules not allowed with --add-modules ALL-MODULE-PATH -err.jlink.version.mismatch=jlink version {0}.{1} does not match target java.base version {2}.{3} +err.jlink.version.mismatch=jlink build ''{0}'' does not match target java.base build ''{1}'' +err.jlink.version.missing=jlink build ''{0}'' cannot find the build signature\ +\ in the java.base specified on module path, likely from an earlier build. err.automatic.module:automatic module cannot be used with jlink: {0} from {1} err.unknown.byte.order:unknown byte order {0} err.launcher.main.class.empty:launcher main class name cannot be empty: {0} diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties index a4b780a15c3..7e3c26fa7b8 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2025, 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 @@ -39,6 +39,7 @@ release-info.argument=|add:=:=:...|del: option is to load release properties from the supplied file.\n\ +\ The specified file is expected to be encoded in UTF-8.\n\ add: is to add properties to the 'release' file.\n\ Any number of = pairs can be passed.\n\ del: is to delete the list of keys in release file. @@ -46,7 +47,8 @@ del: is to delete the list of keys in release file. release-info.usage=\ \ --release-info |add:=:=:...|del:\n\ \ option is to load release properties from\n\ -\ the supplied file.\n\ +\ the supplied file. The specified file is expected\n\ +\ to be encoded in UTF-8.\n\ \ add: is to add properties to the 'release' file.\n\ \ Any number of = pairs can be passed.\n\ \ del: is to delete the list of keys in release file. @@ -59,14 +61,14 @@ Class optimization: convert Class.forName calls to constant loads. class-for-name.usage=\ \ --class-for-name Class optimization: convert Class.forName calls to constant loads. -compress.argument=[:filter=] +compress.argument=[:filter=] compress.description= Compression to use in compressing resources. compress.usage=\ \ --compress Compression to use in compressing resources:\n\ \ Accepted values are:\n\ -\ zip-[0-9], where zip-0 provides no compression,\n\ +\ zip-'{0-9}', where zip-0 provides no compression,\n\ \ and zip-9 provides the best compression.\n\ \ Default is zip-6. @@ -305,15 +307,15 @@ plugin.opt.disable-plugin=\ \ --disable-plugin Disable the plugin mentioned plugin.opt.compress=\ -\ --compress Compression to use in compressing resources:\n\ +\ --compress Compress all resources in the output image:\n\ \ Accepted values are:\n\ -\ zip-[0-9], where zip-0 provides no compression,\n\ +\ zip-'{0-9}', where zip-0 provides no compression,\n\ \ and zip-9 provides the best compression.\n\ \ Default is zip-6.\n\ \ Deprecated values to be removed in a future release:\n\ -\ 0: No compression. Equivalent to zip-0.\n\ +\ 0: No compression. Use zip-0 instead.\n\ \ 1: Constant String Sharing\n\ -\ 2: Equivalent to zip-6. +\ 2: ZIP. Use zip-6 instead. plugin.opt.strip-debug=\ \ -G, --strip-debug Strip debug information diff --git a/src/jdk.jlink/share/man/jlink.md b/src/jdk.jlink/share/man/jlink.md index dc256af43b5..0d16e69c9ef 100644 --- a/src/jdk.jlink/share/man/jlink.md +++ b/src/jdk.jlink/share/man/jlink.md @@ -64,12 +64,15 @@ Developers are responsible for updating their custom runtime images. `--bind-services` : Link service provider modules and their dependencies. -`-c ={0|1|2}` or `--compress={0|1|2}` -: Enable compression of resources: +`-c zip-{0-9}` or `--compress=zip-{0-9}` +: Enable compression of resources. The accepted values are: + zip-{0-9}, where zip-0 provides no compression, + and zip-9 provides the best compression. Default is zip-6. - - `0`: No compression +: Deprecated values to be removed in a future release: + - `0`: No compression. Use zip-0 instead. - `1`: Constant string sharing - - `2`: ZIP + - `2`: ZIP. Use zip-6 instead. `--disable-plugin` *pluginname* : Disables the specified plug-in. See [jlink Plug-ins] for the list of @@ -170,14 +173,18 @@ For a complete list of all available plug-ins, run the command ### Plugin `compress` Options -: `--compress=`{`0`\|`1`\|`2`}\[`:filter=`*pattern-list*\] +: `--compress=zip-`{`0`-`9`}\[`:filter=`*pattern-list*\] Description : Compresses all resources in the output image. + Accepted values are: + zip-{0-9}, where zip-0 provides no compression, + and zip-9 provides the best compression. Default is zip-6. - - Level 0: No compression +: Deprecated values to be removed in a future release: + - Level 0: No compression. Use zip-0 instead. - Level 1: Constant string sharing - - Level 2: ZIP + - Level 2: ZIP. Use zip-6 instead. An optional *pattern-list* filter can be specified to list the pattern of files to include. diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java deleted file mode 100644 index fe8d6bcf34f..00000000000 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2012, 2025, 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 jdk.jpackage.internal; - -import java.util.Optional; - -public class LinuxAppBundler extends AppImageBundler { - public LinuxAppBundler() { - setAppImageSupplier((params, output) -> { - // Order is important! - var app = LinuxFromParams.APPLICATION.fetchFrom(params); - var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - LinuxPackagingPipeline.build(Optional.empty()) - .excludeDirFromCopying(output.getParent()) - .create().execute(BuildEnv.withAppImageDir(env, output), app); - }); - } -} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxBundlingEnvironment.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxBundlingEnvironment.java new file mode 100644 index 00000000000..cfd8ab391bb --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxBundlingEnvironment.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal; + +import static java.util.stream.Collectors.toMap; +import static jdk.jpackage.internal.LinuxFromOptions.createLinuxApplication; +import static jdk.jpackage.internal.LinuxPackagingPipeline.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_LINUX_APP_IMAGE; +import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_LINUX_DEB; +import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_LINUX_RPM; + +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.cli.StandardBundlingOperation; +import jdk.jpackage.internal.model.BundlingOperationDescriptor; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.util.Result; + +public class LinuxBundlingEnvironment extends DefaultBundlingEnvironment { + + public LinuxBundlingEnvironment() { + super(build() + .defaultOperation(() -> { + return LazyLoad.SYS_ENV.value().map(LinuxSystemEnvironment::nativePackageType).map(DESCRIPTORS::get); + }) + .bundler(CREATE_LINUX_APP_IMAGE, LinuxBundlingEnvironment::createAppImage) + .bundler(CREATE_LINUX_DEB, LazyLoad::debSysEnv, LinuxBundlingEnvironment::createDebPackage) + .bundler(CREATE_LINUX_RPM, LazyLoad::rpmSysEnv, LinuxBundlingEnvironment::createRpmPackage)); + } + + private static void createDebPackage(Options options, LinuxDebSystemEnvironment sysEnv) { + + createNativePackage(options, + LinuxFromOptions::createLinuxDebPackage, + buildEnv()::create, + LinuxBundlingEnvironment::buildPipeline, + (env, pkg, outputDir) -> { + return new LinuxDebPackager(env, pkg, outputDir, sysEnv); + }); + } + + private static void createRpmPackage(Options options, LinuxRpmSystemEnvironment sysEnv) { + + createNativePackage(options, + LinuxFromOptions::createLinuxRpmPackage, + buildEnv()::create, + LinuxBundlingEnvironment::buildPipeline, + (env, pkg, outputDir) -> { + return new LinuxRpmPackager(env, pkg, outputDir, sysEnv); + }); + } + + private static void createAppImage(Options options) { + + final var app = createLinuxApplication(options); + + createApplicationImage(options, app, LinuxPackagingPipeline.build(Optional.empty())); + } + + private static PackagingPipeline.Builder buildPipeline(LinuxPackage pkg) { + return LinuxPackagingPipeline.build(Optional.of(pkg)); + } + + private static BuildEnvFromOptions buildEnv() { + return new BuildEnvFromOptions().predefinedAppImageLayout(APPLICATION_LAYOUT); + } + + private static final class LazyLoad { + + static Result debSysEnv() { + return DEB_SYS_ENV; + } + + static Result rpmSysEnv() { + return RPM_SYS_ENV; + } + + private static final Result SYS_ENV = LinuxSystemEnvironment.create(); + + private static final Result DEB_SYS_ENV = LinuxDebSystemEnvironment.create(SYS_ENV); + + private static final Result RPM_SYS_ENV = LinuxRpmSystemEnvironment.create(SYS_ENV); + } + + private static final Map DESCRIPTORS = Stream.of( + CREATE_LINUX_DEB, + CREATE_LINUX_RPM + ).collect(toMap(StandardBundlingOperation::packageType, StandardBundlingOperation::descriptor)); +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java deleted file mode 100644 index 76a08519b48..00000000000 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2012, 2025, 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 jdk.jpackage.internal; - -import java.nio.file.Path; -import java.util.Map; -import java.util.Optional; -import jdk.jpackage.internal.model.LinuxDebPackage; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.StandardPackageType; -import jdk.jpackage.internal.util.Result; - -public class LinuxDebBundler extends LinuxPackageBundler { - - public LinuxDebBundler() { - super(LinuxFromParams.DEB_PACKAGE); - } - - @Override - public String getName() { - return I18N.getString("deb.bundler.name"); - } - - @Override - public String getID() { - return "deb"; - } - - @Override - public Path execute(Map params, Path outputParentDir) throws PackagerException { - - var pkg = LinuxFromParams.DEB_PACKAGE.fetchFrom(params); - - return Packager.build().outputDir(outputParentDir) - .pkg(pkg) - .env(BuildEnvFromParams.BUILD_ENV.fetchFrom(params)) - .pipelineBuilderMutatorFactory((env, _, outputDir) -> { - return new LinuxDebPackager(env, pkg, outputDir, sysEnv.orElseThrow()); - }).execute(LinuxPackagingPipeline.build(Optional.of(pkg))); - } - - @Override - protected Result sysEnv() { - return sysEnv; - } - - @Override - public boolean isDefault() { - return sysEnv.value() - .map(LinuxSystemEnvironment::nativePackageType) - .map(StandardPackageType.LINUX_DEB::equals) - .orElse(false); - } - - private final Result sysEnv = LinuxDebSystemEnvironment.create(SYS_ENV); -} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java index 50e371d5c76..d7b6559abe1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackageBuilder.java @@ -26,7 +26,6 @@ package jdk.jpackage.internal; import java.util.Objects; import java.util.Optional; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxDebPackage; import jdk.jpackage.internal.model.LinuxDebPackageMixin; @@ -36,7 +35,7 @@ final class LinuxDebPackageBuilder { this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } - LinuxDebPackage create() throws ConfigException { + LinuxDebPackage create() { if (pkgBuilder.category().isEmpty()) { pkgBuilder.category(DEFAULTS.category()); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromOptions.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromOptions.java new file mode 100644 index 00000000000..799c92ce2e1 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromOptions.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal; + +import static jdk.jpackage.internal.FromOptions.buildApplicationBuilder; +import static jdk.jpackage.internal.FromOptions.createPackageBuilder; +import static jdk.jpackage.internal.LinuxPackagingPipeline.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.cli.StandardOption.LINUX_APP_CATEGORY; +import static jdk.jpackage.internal.cli.StandardOption.LINUX_DEB_MAINTAINER_EMAIL; +import static jdk.jpackage.internal.cli.StandardOption.LINUX_MENU_GROUP; +import static jdk.jpackage.internal.cli.StandardOption.LINUX_PACKAGE_DEPENDENCIES; +import static jdk.jpackage.internal.cli.StandardOption.LINUX_PACKAGE_NAME; +import static jdk.jpackage.internal.cli.StandardOption.LINUX_RELEASE; +import static jdk.jpackage.internal.cli.StandardOption.LINUX_RPM_LICENSE_TYPE; +import static jdk.jpackage.internal.cli.StandardOption.LINUX_SHORTCUT_HINT; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; + +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.LinuxApplication; +import jdk.jpackage.internal.model.LinuxDebPackage; +import jdk.jpackage.internal.model.LinuxLauncher; +import jdk.jpackage.internal.model.LinuxLauncherMixin; +import jdk.jpackage.internal.model.LinuxRpmPackage; +import jdk.jpackage.internal.model.StandardPackageType; + +final class LinuxFromOptions { + + static LinuxApplication createLinuxApplication(Options options) { + + final var launcherFromOptions = new LauncherFromOptions().faWithDefaultDescription(); + + final var appBuilder = buildApplicationBuilder().create(options, launcherOptions -> { + + final var launcher = launcherFromOptions.create(launcherOptions); + + final var shortcut = LINUX_SHORTCUT_HINT.findIn(launcherOptions); + + return LinuxLauncher.create(launcher, new LinuxLauncherMixin.Stub(shortcut)); + + }, (LinuxLauncher linuxLauncher, Launcher launcher) -> { + return LinuxLauncher.create(launcher, linuxLauncher); + }, APPLICATION_LAYOUT); + + appBuilder.launchers().map(LinuxPackagingPipeline::normalizeShortcuts).ifPresent(appBuilder::launchers); + + return LinuxApplication.create(appBuilder.create()); + } + + static LinuxRpmPackage createLinuxRpmPackage(Options options) { + + final var superPkgBuilder = createLinuxPackageBuilder(options, LINUX_RPM); + + final var pkgBuilder = new LinuxRpmPackageBuilder(superPkgBuilder); + + LINUX_RPM_LICENSE_TYPE.ifPresentIn(options, pkgBuilder::licenseType); + + return pkgBuilder.create(); + } + + static LinuxDebPackage createLinuxDebPackage(Options options) { + + final var superPkgBuilder = createLinuxPackageBuilder(options, LINUX_DEB); + + final var pkgBuilder = new LinuxDebPackageBuilder(superPkgBuilder); + + LINUX_DEB_MAINTAINER_EMAIL.ifPresentIn(options, pkgBuilder::maintainerEmail); + + final var pkg = pkgBuilder.create(); + + // Show warning if license file is missing + if (pkg.licenseFile().isEmpty()) { + Log.verbose(I18N.getString("message.debs-like-licenses")); + } + + return pkg; + } + + private static LinuxPackageBuilder createLinuxPackageBuilder(Options options, StandardPackageType type) { + + final var app = createLinuxApplication(options); + + final var superPkgBuilder = createPackageBuilder(options, app, type); + + final var pkgBuilder = new LinuxPackageBuilder(superPkgBuilder); + + LINUX_PACKAGE_DEPENDENCIES.ifPresentIn(options, pkgBuilder::additionalDependencies); + LINUX_APP_CATEGORY.ifPresentIn(options, pkgBuilder::category); + LINUX_MENU_GROUP.ifPresentIn(options, pkgBuilder::menuGroupName); + LINUX_RELEASE.ifPresentIn(options, pkgBuilder::release); + LINUX_PACKAGE_NAME.ifPresentIn(options, pkgBuilder::literalName); + + return pkgBuilder; + } + +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java deleted file mode 100644 index e9d1416b5c3..00000000000 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.jpackage.internal; - -import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; -import static jdk.jpackage.internal.FromParams.createApplicationBuilder; -import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; -import static jdk.jpackage.internal.FromParams.createPackageBuilder; -import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; -import static jdk.jpackage.internal.FromParams.findLauncherShortcut; -import static jdk.jpackage.internal.LinuxPackagingPipeline.APPLICATION_LAYOUT; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; - -import java.io.IOException; -import java.util.Map; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LinuxApplication; -import jdk.jpackage.internal.model.LinuxDebPackage; -import jdk.jpackage.internal.model.LinuxLauncher; -import jdk.jpackage.internal.model.LinuxLauncherMixin; -import jdk.jpackage.internal.model.LinuxRpmPackage; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.StandardPackageType; - -final class LinuxFromParams { - - private static LinuxApplication createLinuxApplication( - Map params) throws ConfigException, IOException { - final var launcherFromParams = new LauncherFromParams(); - - final var app = createApplicationBuilder(params, toFunction(launcherParams -> { - final var launcher = launcherFromParams.create(launcherParams); - final var shortcut = findLauncherShortcut(LINUX_SHORTCUT_HINT, params, launcherParams); - return LinuxLauncher.create(launcher, new LinuxLauncherMixin.Stub(shortcut)); - }), (LinuxLauncher linuxLauncher, Launcher launcher) -> { - return LinuxLauncher.create(launcher, linuxLauncher); - }, APPLICATION_LAYOUT).create(); - return LinuxApplication.create(app); - } - - private static LinuxPackageBuilder createLinuxPackageBuilder( - Map params, StandardPackageType type) throws ConfigException, IOException { - - final var app = APPLICATION.fetchFrom(params); - - final var superPkgBuilder = createPackageBuilder(params, app, type); - - final var pkgBuilder = new LinuxPackageBuilder(superPkgBuilder); - - LINUX_PACKAGE_DEPENDENCIES.copyInto(params, pkgBuilder::additionalDependencies); - LINUX_CATEGORY.copyInto(params, pkgBuilder::category); - LINUX_MENU_GROUP.copyInto(params, pkgBuilder::menuGroupName); - RELEASE.copyInto(params, pkgBuilder::release); - LINUX_PACKAGE_NAME.copyInto(params, pkgBuilder::literalName); - - return pkgBuilder; - } - - private static LinuxRpmPackage createLinuxRpmPackage( - Map params) throws ConfigException, IOException { - - final var superPkgBuilder = createLinuxPackageBuilder(params, LINUX_RPM); - - final var pkgBuilder = new LinuxRpmPackageBuilder(superPkgBuilder); - - LICENSE_TYPE.copyInto(params, pkgBuilder::licenseType); - - return pkgBuilder.create(); - } - - private static LinuxDebPackage createLinuxDebPackage( - Map params) throws ConfigException, IOException { - - final var superPkgBuilder = createLinuxPackageBuilder(params, LINUX_DEB); - - final var pkgBuilder = new LinuxDebPackageBuilder(superPkgBuilder); - - MAINTAINER_EMAIL.copyInto(params, pkgBuilder::maintainerEmail); - - final var pkg = pkgBuilder.create(); - - // Show warning if license file is missing - if (pkg.licenseFile().isEmpty()) { - Log.verbose(I18N.getString("message.debs-like-licenses")); - } - - return pkg; - } - - static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( - LinuxFromParams::createLinuxApplication); - - static final BundlerParamInfo RPM_PACKAGE = createPackageBundlerParam( - LinuxFromParams::createLinuxRpmPackage); - - static final BundlerParamInfo DEB_PACKAGE = createPackageBundlerParam( - LinuxFromParams::createLinuxDebPackage); - - private static final BundlerParamInfo LINUX_SHORTCUT_HINT = createStringBundlerParam( - Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId()); - - private static final BundlerParamInfo LINUX_CATEGORY = createStringBundlerParam( - Arguments.CLIOptions.LINUX_CATEGORY.getId()); - - private static final BundlerParamInfo LINUX_PACKAGE_DEPENDENCIES = createStringBundlerParam( - Arguments.CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId()); - - private static final BundlerParamInfo LINUX_MENU_GROUP = createStringBundlerParam( - Arguments.CLIOptions.LINUX_MENU_GROUP.getId()); - - private static final BundlerParamInfo RELEASE = createStringBundlerParam( - Arguments.CLIOptions.RELEASE.getId()); - - private static final BundlerParamInfo LINUX_PACKAGE_NAME = createStringBundlerParam( - Arguments.CLIOptions.LINUX_BUNDLE_NAME.getId()); - - private static final BundlerParamInfo LICENSE_TYPE = createStringBundlerParam( - Arguments.CLIOptions.LINUX_RPM_LICENSE_TYPE.getId()); - - private static final BundlerParamInfo MAINTAINER_EMAIL = createStringBundlerParam( - Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId()); -} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index cc00d7816f5..bc7c301ace2 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -32,12 +32,11 @@ import java.util.Optional; import java.util.regex.Pattern; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ApplicationLayout; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxApplication; import jdk.jpackage.internal.model.LinuxPackage; -import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.model.LinuxPackageMixin; import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.model.StandardPackageType; final class LinuxPackageBuilder { @@ -46,20 +45,17 @@ final class LinuxPackageBuilder { this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } - LinuxPackage create() throws ConfigException { - if (literalName != null) { - pkgBuilder.name(literalName); - } else { + LinuxPackage create() { + pkgBuilder.name(Optional.ofNullable(literalName).orElseGet(() -> { // Lower case and turn spaces/underscores into dashes - pkgBuilder.name(pkgBuilder.create().packageName().toLowerCase().replaceAll("[ _]", "-")); - } + return pkgBuilder.create().packageName().toLowerCase().replaceAll("[ _]", "-"); + })); final var tmpPkg = pkgBuilder.create(); - final var stdPkgType = tmpPkg.asStandardPackageType(); - if (stdPkgType.isPresent()) { - validatePackageName(tmpPkg.packageName(), stdPkgType.orElseThrow()); - } + tmpPkg.asStandardPackageType().ifPresent(stdPkgType -> { + validatePackageName(tmpPkg.packageName(), stdPkgType); + }); final AppImageLayout relativeInstalledLayout; if (create(tmpPkg).isInstallDirInUsrTree()) { @@ -81,12 +77,12 @@ final class LinuxPackageBuilder { .create()); } - private LinuxPackage create(Package pkg) throws ConfigException { + private LinuxPackage create(Package pkg) { return LinuxPackage.create(pkg, new LinuxPackageMixin.Stub( Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName), - Optional.ofNullable(category), + category(), Optional.ofNullable(additionalDependencies), - Optional.ofNullable(release), + release(), pkg.asStandardPackageType().map(LinuxPackageArch::getValue).orElseThrow())); } @@ -137,8 +133,7 @@ final class LinuxPackageBuilder { lib.resolve("lib/libapplauncher.so")); } - private static void validatePackageName(String packageName, - StandardPackageType pkgType) throws ConfigException { + private static void validatePackageName(String packageName, StandardPackageType pkgType) { switch (pkgType) { case LINUX_DEB -> { // @@ -192,7 +187,7 @@ final class LinuxPackageBuilder { private final PackageBuilder pkgBuilder; - private static final Defaults DEFAULTS = new Defaults(I18N.getString( - "param.menu-group.default")); - + // Should be one of https://specifications.freedesktop.org/menu/latest/category-registry.html#main-category-registry + // The category is an ID, not a localizable string + private static final Defaults DEFAULTS = new Defaults("Utility"); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java deleted file mode 100644 index 1f674c0be11..00000000000 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2019, 2025, 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 jdk.jpackage.internal; - -import java.util.Map; -import java.util.Objects; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LinuxPackage; -import jdk.jpackage.internal.util.Result; - -abstract class LinuxPackageBundler extends AbstractBundler { - - LinuxPackageBundler(BundlerParamInfo pkgParam) { - this.pkgParam = Objects.requireNonNull(pkgParam); - } - - @Override - public final boolean validate(Map params) - throws ConfigException { - - // Order is important! - pkgParam.fetchFrom(params); - BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - - LinuxSystemEnvironment sysEnv; - try { - sysEnv = sysEnv().orElseThrow(); - } catch (RuntimeException ex) { - throw ConfigException.rethrowConfigException(ex); - } - - if (!isDefault()) { - Log.verbose(I18N.format( - "message.not-default-bundler-no-dependencies-lookup", - getName())); - } else if (!sysEnv.soLookupAvailable()) { - final String advice; - if ("deb".equals(getID())) { - advice = "message.deb-ldd-not-available.advice"; - } else { - advice = "message.rpm-ldd-not-available.advice"; - } - // Let user know package dependencies will not be generated. - Log.error(String.format("%s\n%s", I18N.getString( - "message.ldd-not-available"), I18N.getString(advice))); - } - - return true; - } - - @Override - public final String getBundleType() { - return "INSTALLER"; - } - - @Override - public boolean supported(boolean runtimeInstaller) { - return sysEnv().hasValue(); - } - - protected abstract Result sysEnv(); - - private final BundlerParamInfo pkgParam; - - static final Result SYS_ENV = LinuxSystemEnvironment.create(); -} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java index 806592904d1..af7f5288cc5 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java @@ -40,7 +40,6 @@ import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxPackage; -import jdk.jpackage.internal.model.PackagerException; abstract class LinuxPackager implements Consumer { @@ -95,7 +94,7 @@ abstract class LinuxPackager implements Consumer { + // Return "true" if shortcut is not configured for the launcher. + return launcher.shortcut().isEmpty(); + }, (LinuxLauncher launcher) -> { + return launcher.shortcut().flatMap(LauncherShortcut::startupDirectory); + }, (launcher, shortcut) -> { + return LinuxLauncher.create(launcher, new LinuxLauncherMixin.Stub(Optional.of(new LauncherShortcut(shortcut)))); + }); + } + private static void writeLauncherLib( AppImageBuildEnv env) throws IOException { @@ -90,6 +106,15 @@ final class LinuxPackagingPipeline { }); } + private static final ApplicationLayout LINUX_APPLICATION_LAYOUT = ApplicationLayout.build() + .launchersDirectory("bin") + .appDirectory("lib/app") + .runtimeDirectory("lib/runtime") + .desktopIntegrationDirectory("lib") + .appModsDirectory("lib/app/mods") + .contentDirectory("lib") + .create(); + static final LinuxApplicationLayout APPLICATION_LAYOUT = LinuxApplicationLayout.create( - ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT, Path.of("lib/libapplauncher.so")); + LINUX_APPLICATION_LAYOUT, Path.of("lib/libapplauncher.so")); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java deleted file mode 100644 index c134aa91d6a..00000000000 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2012, 2025, 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 jdk.jpackage.internal; - -import java.nio.file.Path; -import java.util.Map; -import java.util.Optional; -import jdk.jpackage.internal.model.LinuxRpmPackage; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.StandardPackageType; -import jdk.jpackage.internal.util.Result; - - -public class LinuxRpmBundler extends LinuxPackageBundler { - - public LinuxRpmBundler() { - super(LinuxFromParams.RPM_PACKAGE); - } - - @Override - public String getName() { - return I18N.getString("rpm.bundler.name"); - } - - @Override - public String getID() { - return "rpm"; - } - - @Override - public Path execute(Map params, Path outputParentDir) throws PackagerException { - - var pkg = LinuxFromParams.RPM_PACKAGE.fetchFrom(params); - - return Packager.build().outputDir(outputParentDir) - .pkg(pkg) - .env(BuildEnvFromParams.BUILD_ENV.fetchFrom(params)) - .pipelineBuilderMutatorFactory((env, _, outputDir) -> { - return new LinuxRpmPackager(env, pkg, outputDir, sysEnv.orElseThrow()); - }).execute(LinuxPackagingPipeline.build(Optional.of(pkg))); - } - - @Override - protected Result sysEnv() { - return sysEnv; - } - - @Override - public boolean isDefault() { - return sysEnv.value() - .map(LinuxSystemEnvironment::nativePackageType) - .map(StandardPackageType.LINUX_RPM::equals) - .orElse(false); - } - - private final Result sysEnv = LinuxRpmSystemEnvironment.create(SYS_ENV); -} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java index bc361eac759..f97a7741e42 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackageBuilder.java @@ -26,7 +26,6 @@ package jdk.jpackage.internal; import java.util.Objects; import java.util.Optional; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxRpmPackage; import jdk.jpackage.internal.model.LinuxRpmPackageMixin; @@ -36,7 +35,7 @@ final class LinuxRpmPackageBuilder { this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } - LinuxRpmPackage create() throws ConfigException { + LinuxRpmPackage create() { if (pkgBuilder.release().isEmpty()) { pkgBuilder.release("1"); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java index c84b5e3bbf5..3c654f604c2 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal.model; +import static jdk.jpackage.internal.cli.StandardAppImageFileOption.LINUX_LAUNCHER_SHORTCUT; + import java.util.HashMap; import java.util.Map; import jdk.jpackage.internal.util.CompositeProxy; @@ -39,7 +41,7 @@ public interface LinuxLauncher extends Launcher, LinuxLauncherMixin { default Map extraAppImageFileData() { Map map = new HashMap<>(); shortcut().ifPresent(shortcut -> { - shortcut.store(SHORTCUT_ID, map::put); + shortcut.store(LINUX_LAUNCHER_SHORTCUT.getName(), map::put); }); return map; } @@ -55,6 +57,4 @@ public interface LinuxLauncher extends Launcher, LinuxLauncherMixin { public static LinuxLauncher create(Launcher launcher, LinuxLauncherMixin mixin) { return CompositeProxy.create(LinuxLauncher.class, launcher, mixin); } - - public static final String SHORTCUT_ID = "linux-shortcut"; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java index 5bcf57194f6..056e3b89527 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java @@ -34,6 +34,12 @@ public interface LinuxPackageMixin { /** * Gets the name of the start menu group where to create shortcuts for * application launchers of this package. + *

    + * It sets the value of the "Categories" property in .desktop files of the + * package. + *

    + * Should be one of the values from https://specifications.freedesktop.org/menu/latest/category-registry.html * * @return the name of the start menu group where to create shortcuts for * application launchers of this package @@ -44,6 +50,13 @@ public interface LinuxPackageMixin { /** * Gets the category of this package. + *

    + * For RPM packages this is the value of the optional "Group" property. + *

    + * For DEB packages this is the value of the mandatory "Section" property. + * The + * present list of recognized values. * * @return the category of this package */ @@ -62,7 +75,7 @@ public interface LinuxPackageMixin { * Gets the release of this package. Returns an empty {@link Optional} instance * if this package doesn't have a release. *

    - * For RPM packages, this is the value of a "Release" property in spec file. RPM + * For RPM packages, this is the value of the "Release" property in spec file. RPM * packages always have a release. *

    * For DEB packages, this is an optional {@code debian_revision} component of a diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties index fbc83ba2e10..3aabe1f4ba5 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/LinuxResources.properties @@ -23,12 +23,7 @@ # questions. # # -app.bundler.name=Linux Application Image -deb.bundler.name=DEB Bundle -rpm.bundler.name=RPM Bundle - param.license-type.default=Unknown -param.menu-group.default=Unknown resource.deb-control-file=DEB control file resource.deb-preinstall-script=DEB preinstall script @@ -59,7 +54,6 @@ message.output-to-location=Package (.deb) saved to: {0}. message.debs-like-licenses=Debian packages should specify a license. The absence of a license will cause some linux distributions to complain about the quality of the application. message.outputting-bundle-location=Generating RPM for installer to: {0}. message.output-bundle-location=Package (.rpm) saved to: {0}. -message.creating-association-with-null-extension=Creating association with null extension. message.ldd-not-available=ldd command not found. Package dependencies will not be generated. message.deb-ldd-not-available.advice=Install "libc-bin" DEB package to get ldd. diff --git a/src/jdk.jpackage/linux/classes/module-info.java.extra b/src/jdk.jpackage/linux/classes/module-info.java.extra index d32314b0429..7bef2286214 100644 --- a/src/jdk.jpackage/linux/classes/module-info.java.extra +++ b/src/jdk.jpackage/linux/classes/module-info.java.extra @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,5 @@ * questions. */ -provides jdk.jpackage.internal.Bundler with - jdk.jpackage.internal.LinuxAppBundler, - jdk.jpackage.internal.LinuxDebBundler, - jdk.jpackage.internal.LinuxRpmBundler; - +provides jdk.jpackage.internal.cli.CliBundlingEnvironment with + jdk.jpackage.internal.LinuxBundlingEnvironment; diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigningConfigBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigningConfigBuilder.java index bb043830f3c..6fc7fe004c2 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigningConfigBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigningConfigBuilder.java @@ -28,7 +28,6 @@ import java.nio.file.Path; import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.model.AppImageSigningConfig; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LauncherStartupInfo; final class AppImageSigningConfigBuilder { @@ -62,21 +61,20 @@ final class AppImageSigningConfigBuilder { return this; } - Optional create() throws ConfigException { - final var identityCfg = signingIdentityBuilder.create(); - if (identityCfg.isEmpty()) { - return Optional.empty(); - } else { + Optional create() { + return signingIdentityBuilder.create().map(cfg -> { final var validatedEntitlements = validatedEntitlements(); - return identityCfg.map(cfg -> { - return new AppImageSigningConfig.Stub(cfg.identity(), signingIdentifierPrefix, - validatedEntitlements, cfg.keychain().map(Keychain::name), - Optional.ofNullable(entitlementsResourceName).orElse("entitlements.plist")); - }); - } + return new AppImageSigningConfig.Stub( + Objects.requireNonNull(cfg.identity()), + Objects.requireNonNull(signingIdentifierPrefix), + validatedEntitlements, + cfg.keychain().map(Keychain::name), + Optional.ofNullable(entitlementsResourceName).orElse("entitlements.plist") + ); + }); } - private Optional validatedEntitlements() throws ConfigException { + private Optional validatedEntitlements() { return Optional.ofNullable(entitlements); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java deleted file mode 100644 index cce35ece117..00000000000 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2012, 2025, 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 jdk.jpackage.internal; - -import static jdk.jpackage.internal.StandardBundlerParam.OUTPUT_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; - -import java.util.Map; -import java.util.Optional; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.util.function.ExceptionBox; - -public class MacAppBundler extends AppImageBundler { - public MacAppBundler() { - setAppImageSupplier((params, output) -> { - - // Order is important! - final var app = MacFromParams.APPLICATION.fetchFrom(params); - final BuildEnv env; - - if (StandardBundlerParam.hasPredefinedAppImage(params)) { - env = MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params); - final var pkg = MacPackagingPipeline.createSignAppImagePackage(app, env); - MacPackagingPipeline.build(Optional.of(pkg)).create().execute(env, pkg, output); - } else { - env = BuildEnv.withAppImageDir(MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params), output); - MacPackagingPipeline.build(Optional.empty()) - .excludeDirFromCopying(output.getParent()) - .excludeDirFromCopying(OUTPUT_DIR.fetchFrom(params)).create().execute(env, app); - } - - }); - setParamsValidator(MacAppBundler::doValidate); - } - - private static void doValidate(Map params) - throws ConfigException { - - try { - MacFromParams.APPLICATION.fetchFrom(params); - } catch (ExceptionBox ex) { - if (ex.getCause() instanceof ConfigException cfgEx) { - throw cfgEx; - } else { - throw ex; - } - } - - if (StandardBundlerParam.hasPredefinedAppImage(params)) { - if (!Optional.ofNullable( - SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) { - throw new ConfigException( - I18N.getString("error.app-image.mac-sign.required"), - null); - } - } - } -} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index 226bb9e8134..5f126305aed 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -28,17 +28,15 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.List; -import java.util.Set; import java.util.Objects; import java.util.Optional; +import java.util.Set; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.AppImageSigningConfig; import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacApplicationMixin; -import jdk.jpackage.internal.model.AppImageLayout; -import jdk.jpackage.internal.model.AppImageSigningConfig; final class MacApplicationBuilder { @@ -92,7 +90,7 @@ final class MacApplicationBuilder { return this; } - MacApplication create() throws ConfigException { + MacApplication create() { if (externalInfoPlistFile != null) { return createCopyForExternalInfoPlistFile().create(); } @@ -136,7 +134,7 @@ final class MacApplicationBuilder { return true; } - private static void validateAppVersion(Application app) throws ConfigException { + private static void validateAppVersion(Application app) { try { CFBundleVersion.of(app.version()); } catch (IllegalArgumentException ex) { @@ -156,7 +154,7 @@ final class MacApplicationBuilder { } } - private MacApplicationBuilder createCopyForExternalInfoPlistFile() throws ConfigException { + private MacApplicationBuilder createCopyForExternalInfoPlistFile() { try { final var plistFile = AppImageInfoPListFile.loadFromInfoPList(externalInfoPlistFile); @@ -187,15 +185,11 @@ final class MacApplicationBuilder { } } - private Optional createSigningConfig() throws ConfigException { - if (signingBuilder != null) { - return signingBuilder.create(); - } else { - return Optional.empty(); - } + private Optional createSigningConfig() { + return Optional.ofNullable(signingBuilder).flatMap(AppImageSigningConfigBuilder::create); } - private String validatedBundleName() throws ConfigException { + private String validatedBundleName() { final var value = Optional.ofNullable(bundleName).orElseGet(() -> { final var appName = app.name(); // Commented out for backward compatibility @@ -214,7 +208,7 @@ final class MacApplicationBuilder { return value; } - private String validatedBundleIdentifier() throws ConfigException { + private String validatedBundleIdentifier() { final var value = Optional.ofNullable(bundleIdentifier).orElseGet(() -> { return app.mainLauncher() .flatMap(Launcher::startupInfo) @@ -238,16 +232,12 @@ final class MacApplicationBuilder { return value; } - private String validatedCategory() throws ConfigException { + private String validatedCategory() { return "public.app-category." + Optional.ofNullable(category).orElseGet(DEFAULTS::category); } - private Optional validatedIcon() throws ConfigException { - if (icon != null) { - LauncherBuilder.validateIcon(icon); - } - - return Optional.ofNullable(icon); + private Optional validatedIcon() { + return Optional.ofNullable(icon).map(LauncherBuilder::validateIcon); } private record Defaults(String category) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java new file mode 100644 index 00000000000..371a3c7307a --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal; + +import static jdk.jpackage.internal.MacFromOptions.createMacApplication; +import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.MacPackagingPipeline.createSignAppImagePackage; +import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_MAC_APP_IMAGE; +import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_MAC_DMG; +import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_MAC_PKG; +import static jdk.jpackage.internal.cli.StandardBundlingOperation.SIGN_MAC_APP_IMAGE; + +import java.util.Optional; +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.model.MacPackage; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.util.Result; + +public class MacBundlingEnvironment extends DefaultBundlingEnvironment { + + public MacBundlingEnvironment() { + super(build() + .defaultOperation(CREATE_MAC_DMG) + .bundler(SIGN_MAC_APP_IMAGE, MacBundlingEnvironment::signAppImage) + .bundler(CREATE_MAC_APP_IMAGE, MacBundlingEnvironment::createAppImage) + .bundler(CREATE_MAC_DMG, LazyLoad::dmgSysEnv, MacBundlingEnvironment::createDmdPackage) + .bundler(CREATE_MAC_PKG, MacBundlingEnvironment::createPkgPackage)); + } + + private static void createDmdPackage(Options options, MacDmgSystemEnvironment sysEnv) { + createNativePackage(options, + MacFromOptions::createMacDmgPackage, + buildEnv()::create, + MacBundlingEnvironment::buildPipeline, + (env, pkg, outputDir) -> { + Log.verbose(I18N.format("message.building-dmg", pkg.app().name())); + return new MacDmgPackager(env, pkg, outputDir, sysEnv); + }); + } + + private static void createPkgPackage(Options options) { + createNativePackage(options, + MacFromOptions::createMacPkgPackage, + buildEnv()::create, + MacBundlingEnvironment::buildPipeline, + (env, pkg, outputDir) -> { + Log.verbose(I18N.format("message.building-pkg", pkg.app().name())); + return new MacPkgPackager(env, pkg, outputDir); + }); + } + + private static void signAppImage(Options options) { + + final var app = createMacApplication(options); + + final var env = buildEnv().create(options, app); + + final var pkg = createSignAppImagePackage(app, env); + + buildPipeline(pkg).create().execute(env, pkg, env.appImageDir()); + } + + private static void createAppImage(Options options) { + + final var app = createMacApplication(options); + + createApplicationImage(options, app, MacPackagingPipeline.build(Optional.empty())); + } + + private static PackagingPipeline.Builder buildPipeline(Package pkg) { + return MacPackagingPipeline.build(Optional.of(pkg)); + } + + private static BuildEnvFromOptions buildEnv() { + return new BuildEnvFromOptions() + .predefinedAppImageLayout(APPLICATION_LAYOUT) + .predefinedRuntimeImageLayout(MacPackage::guessRuntimeLayout); + } + + private static final class LazyLoad { + + static Result dmgSysEnv() { + return DMG_SYS_ENV; + } + + private static final Result DMG_SYS_ENV = MacDmgSystemEnvironment.create(); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java deleted file mode 100644 index 0ddb987dbee..00000000000 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2012, 2025, 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 jdk.jpackage.internal; - -import java.nio.file.Path; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.MacDmgPackage; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.util.Result; - -public class MacDmgBundler extends MacBaseInstallerBundler { - - @Override - public String getName() { - return I18N.getString("dmg.bundler.name"); - } - - @Override - public String getID() { - return "dmg"; - } - - @Override - public boolean validate(Map params) - throws ConfigException { - try { - Objects.requireNonNull(params); - - MacFromParams.DMG_PACKAGE.fetchFrom(params); - - //run basic validation to ensure requirements are met - //we are not interested in return code, only possible exception - validateAppImageAndBundeler(params); - - return true; - } catch (RuntimeException re) { - if (re.getCause() instanceof ConfigException) { - throw (ConfigException) re.getCause(); - } else { - throw new ConfigException(re); - } - } - } - - @Override - public Path execute(Map params, - Path outputParentDir) throws PackagerException { - - var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); - - Log.verbose(I18N.format("message.building-dmg", pkg.app().name())); - - return Packager.build().outputDir(outputParentDir) - .pkg(pkg) - .env(MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params)) - .pipelineBuilderMutatorFactory((env, _, outputDir) -> { - return new MacDmgPackager(env, pkg, outputDir, sysEnv.orElseThrow()); - }).execute(MacPackagingPipeline.build(Optional.of(pkg))); - } - - @Override - public boolean supported(boolean runtimeInstaller) { - return sysEnv.hasValue(); - } - - @Override - public boolean isDefault() { - return true; - } - - private final Result sysEnv = MacDmgSystemEnvironment.create(); -} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java index c2b9c25f327..10754b1f1b6 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java @@ -28,7 +28,6 @@ import java.nio.file.Path; import java.util.List; import java.util.Objects; import java.util.Optional; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.MacDmgPackageMixin; @@ -52,7 +51,7 @@ final class MacDmgPackageBuilder { return Optional.ofNullable(dmgContent).orElseGet(List::of); } - MacDmgPackage create() throws ConfigException { + MacDmgPackage create() { final var pkg = pkgBuilder.create(); return MacDmgPackage.create(pkg, new MacDmgPackageMixin.Stub( diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index 6e13a2ff0c1..4ccc459109f 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -30,6 +30,7 @@ import static jdk.jpackage.internal.util.PathUtils.normalizedAbsolutePathString; import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.LinkOption; import java.nio.file.Path; import java.text.MessageFormat; import java.util.Base64; @@ -288,7 +289,7 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, // Copy app image, since we did not create DMG with it, but instead we created // empty one. if (copyAppImage) { - FileUtils.copyRecursive(srcFolder, mountedVolume); + FileUtils.copyRecursive(srcFolder, mountedVolume, LinkOption.NOFOLLOW_LINKS); } try { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java index c86b3a15cbb..7b9e5478f74 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFileAssociationBuilder.java @@ -27,15 +27,13 @@ package jdk.jpackage.internal; import java.util.List; import java.util.Objects; import java.util.Optional; - -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.MacFileAssociation; import jdk.jpackage.internal.model.MacFileAssociationMixin; final class MacFileAssociationBuilder { - MacFileAssociation create(FileAssociation fa) throws ConfigException { + MacFileAssociation create(FileAssociation fa) { Objects.requireNonNull(fa); final var mixin = new MacFileAssociationMixin.Stub( diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java new file mode 100644 index 00000000000..074014dede0 --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal; + +import static jdk.jpackage.internal.FromOptions.buildApplicationBuilder; +import static jdk.jpackage.internal.FromOptions.createPackageBuilder; +import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasJliLib; +import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasNoBinDir; +import static jdk.jpackage.internal.cli.StandardBundlingOperation.SIGN_MAC_APP_IMAGE; +import static jdk.jpackage.internal.cli.StandardOption.ICON; +import static jdk.jpackage.internal.cli.StandardOption.APPCLASS; +import static jdk.jpackage.internal.cli.StandardOption.MAC_APP_CATEGORY; +import static jdk.jpackage.internal.cli.StandardOption.MAC_APP_IMAGE_SIGN_IDENTITY; +import static jdk.jpackage.internal.cli.StandardOption.MAC_APP_STORE; +import static jdk.jpackage.internal.cli.StandardOption.MAC_BUNDLE_IDENTIFIER; +import static jdk.jpackage.internal.cli.StandardOption.MAC_BUNDLE_NAME; +import static jdk.jpackage.internal.cli.StandardOption.MAC_BUNDLE_SIGNING_PREFIX; +import static jdk.jpackage.internal.cli.StandardOption.MAC_DMG_CONTENT; +import static jdk.jpackage.internal.cli.StandardOption.MAC_ENTITLEMENTS; +import static jdk.jpackage.internal.cli.StandardOption.MAC_INSTALLER_SIGN_IDENTITY; +import static jdk.jpackage.internal.cli.StandardOption.MAC_SIGN; +import static jdk.jpackage.internal.cli.StandardOption.MAC_SIGNING_KEYCHAIN; +import static jdk.jpackage.internal.cli.StandardOption.MAC_SIGNING_KEY_NAME; +import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_RUNTIME_IMAGE; +import static jdk.jpackage.internal.model.MacPackage.RUNTIME_BUNDLE_LAYOUT; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; +import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.ApplicationBuilder.MainLauncherStartupInfo; +import jdk.jpackage.internal.SigningIdentityBuilder.ExpiredCertificateException; +import jdk.jpackage.internal.SigningIdentityBuilder.StandardCertificateSelector; +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.cli.StandardFaOption; +import jdk.jpackage.internal.model.ApplicationLaunchers; +import jdk.jpackage.internal.model.ExternalApplication; +import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.MacDmgPackage; +import jdk.jpackage.internal.model.MacFileAssociation; +import jdk.jpackage.internal.model.MacLauncher; +import jdk.jpackage.internal.model.MacPackage; +import jdk.jpackage.internal.model.MacPkgPackage; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.RuntimeLayout; +import jdk.jpackage.internal.util.Result; +import jdk.jpackage.internal.util.function.ExceptionBox; + + +final class MacFromOptions { + + static MacApplication createMacApplication(Options options) { + return createMacApplicationInternal(options).app(); + } + + static MacDmgPackage createMacDmgPackage(Options options) { + + final var app = createMacApplicationInternal(options); + + final var superPkgBuilder = createMacPackageBuilder(options, app, MAC_DMG); + + final var pkgBuilder = new MacDmgPackageBuilder(superPkgBuilder); + + MAC_DMG_CONTENT.ifPresentIn(options, pkgBuilder::dmgContent); + + return pkgBuilder.create(); + } + + static MacPkgPackage createMacPkgPackage(Options options) { + + // + // One of "MacSignTest.testExpiredCertificate" test cases expects + // two error messages about expired certificates in the output: one for + // certificate for signing an app image, another certificate for signing a PKG. + // So creation of a PKG package is a bit messy. + // + + final boolean sign = MAC_SIGN.findIn(options).orElse(false); + final boolean appStore = MAC_APP_STORE.findIn(options).orElse(false); + + final var appResult = Result.create(() -> createMacApplicationInternal(options)); + + final Optional pkgBuilder; + if (appResult.hasValue()) { + final var superPkgBuilder = createMacPackageBuilder(options, appResult.orElseThrow(), MAC_PKG); + pkgBuilder = Optional.of(new MacPkgPackageBuilder(superPkgBuilder)); + } else { + // Failed to create an app. Is it because of the expired certificate? + rethrowIfNotExpiredCertificateException(appResult); + // Yes, the certificate for signing the app image has expired. + // Keep going, try to create a signing config for the package. + pkgBuilder = Optional.empty(); + } + + if (sign) { + final var signingIdentityBuilder = createSigningIdentityBuilder(options); + MAC_INSTALLER_SIGN_IDENTITY.ifPresentIn(options, signingIdentityBuilder::signingIdentity); + MAC_SIGNING_KEY_NAME.findIn(options).ifPresent(userName -> { + final StandardCertificateSelector domain; + if (appStore) { + domain = StandardCertificateSelector.APP_STORE_PKG_INSTALLER; + } else { + domain = StandardCertificateSelector.PKG_INSTALLER; + } + + signingIdentityBuilder.certificateSelector(StandardCertificateSelector.create(userName, domain)); + }); + + if (pkgBuilder.isPresent()) { + pkgBuilder.orElseThrow().signingBuilder(signingIdentityBuilder); + } else { + // + // The certificate for signing the app image has expired. Can not create a + // package because there is no app. + // Try to create a signing config for the package and see if the certificate for + // signing the package is also expired. + // + + final var expiredAppCertException = appResult.firstError().orElseThrow(); + + final var pkgSignConfigResult = Result.create(signingIdentityBuilder::create); + try { + rethrowIfNotExpiredCertificateException(pkgSignConfigResult); + // The certificate for the package signing config is also expired! + } catch (RuntimeException ex) { + // Some error occurred trying to configure the signing config for the package. + // Ignore it, bail out with the first error. + rethrowUnchecked(expiredAppCertException); + } + + Log.error(pkgSignConfigResult.firstError().orElseThrow().getMessage()); + rethrowUnchecked(expiredAppCertException); + } + } + + return pkgBuilder.orElseThrow().create(); + } + + private record ApplicationWithDetails(MacApplication app, Optional externalApp) { + ApplicationWithDetails { + Objects.requireNonNull(app); + Objects.requireNonNull(externalApp); + } + } + + private static ApplicationWithDetails createMacApplicationInternal(Options options) { + + final var predefinedRuntimeLayout = PREDEFINED_RUNTIME_IMAGE.findIn(options) + .map(MacPackage::guessRuntimeLayout); + + predefinedRuntimeLayout.ifPresent(layout -> { + validateRuntimeHasJliLib(layout); + if (MAC_APP_STORE.containsIn(options)) { + validateRuntimeHasNoBinDir(layout); + } + }); + + final var launcherFromOptions = new LauncherFromOptions().faMapper(MacFromOptions::createMacFa); + + final var superAppBuilder = buildApplicationBuilder() + .runtimeLayout(RUNTIME_BUNDLE_LAYOUT) + .predefinedRuntimeLayout(predefinedRuntimeLayout.map(RuntimeLayout::unresolve).orElse(null)) + .create(options, launcherOptions -> { + var launcher = launcherFromOptions.create(launcherOptions); + return MacLauncher.create(launcher); + }, (MacLauncher _, Launcher launcher) -> { + return MacLauncher.create(launcher); + }, APPLICATION_LAYOUT); + + if (PREDEFINED_APP_IMAGE.containsIn(options)) { + // Set the main launcher start up info. + // AppImageFile assumes the main launcher start up info is available when + // it is constructed from Application instance. + // This happens when jpackage signs predefined app image. + final var appImageFileOptions = superAppBuilder.externalApplication().orElseThrow().extra(); + final var mainLauncherStartupInfo = new MainLauncherStartupInfo(APPCLASS.getFrom(appImageFileOptions)); + final var launchers = superAppBuilder.launchers().orElseThrow(); + final var mainLauncher = ApplicationBuilder.overrideLauncherStartupInfo(launchers.mainLauncher(), mainLauncherStartupInfo); + superAppBuilder.launchers(new ApplicationLaunchers(MacLauncher.create(mainLauncher), launchers.additionalLaunchers())); + } + + final var app = superAppBuilder.create(); + + final var appBuilder = new MacApplicationBuilder(app); + + PREDEFINED_APP_IMAGE.findIn(options) + .map(MacBundle::new) + .map(MacBundle::infoPlistFile) + .ifPresent(appBuilder::externalInfoPlistFile); + + ICON.ifPresentIn(options, appBuilder::icon); + MAC_BUNDLE_NAME.ifPresentIn(options, appBuilder::bundleName); + MAC_BUNDLE_IDENTIFIER.ifPresentIn(options, appBuilder::bundleIdentifier); + MAC_APP_CATEGORY.ifPresentIn(options, appBuilder::category); + + final boolean sign; + final boolean appStore; + + if (PREDEFINED_APP_IMAGE.containsIn(options) && OptionUtils.bundlingOperation(options) != SIGN_MAC_APP_IMAGE) { + final var appImageFileOptions = superAppBuilder.externalApplication().orElseThrow().extra(); + sign = MAC_SIGN.getFrom(appImageFileOptions); + appStore = MAC_APP_STORE.getFrom(appImageFileOptions); + } else { + sign = MAC_SIGN.getFrom(options); + appStore = MAC_APP_STORE.getFrom(options); + } + + appBuilder.appStore(appStore); + + if (sign) { + final var signingIdentityBuilder = createSigningIdentityBuilder(options); + MAC_APP_IMAGE_SIGN_IDENTITY.ifPresentIn(options, signingIdentityBuilder::signingIdentity); + MAC_SIGNING_KEY_NAME.findIn(options).ifPresent(userName -> { + final StandardCertificateSelector domain; + if (appStore) { + domain = StandardCertificateSelector.APP_STORE_APP_IMAGE; + } else { + domain = StandardCertificateSelector.APP_IMAGE; + } + + signingIdentityBuilder.certificateSelector(StandardCertificateSelector.create(userName, domain)); + }); + + final var signingBuilder = new AppImageSigningConfigBuilder(signingIdentityBuilder); + if (appStore) { + signingBuilder.entitlementsResourceName("sandbox.plist"); + } + + app.mainLauncher().flatMap(Launcher::startupInfo).ifPresentOrElse( + signingBuilder::signingIdentifierPrefix, + () -> { + // Runtime installer does not have the main launcher, use + // 'bundleIdentifier' as the prefix by default. + var bundleIdentifier = appBuilder.create().bundleIdentifier(); + signingBuilder.signingIdentifierPrefix(bundleIdentifier + "."); + }); + MAC_BUNDLE_SIGNING_PREFIX.ifPresentIn(options, signingBuilder::signingIdentifierPrefix); + + MAC_ENTITLEMENTS.ifPresentIn(options, signingBuilder::entitlements); + + appBuilder.signingBuilder(signingBuilder); + } + + return new ApplicationWithDetails(appBuilder.create(), superAppBuilder.externalApplication()); + } + + private static MacPackageBuilder createMacPackageBuilder(Options options, ApplicationWithDetails app, PackageType type) { + + final var builder = new MacPackageBuilder(createPackageBuilder(options, app.app(), type)); + + app.externalApp() + .map(ExternalApplication::extra) + .flatMap(MAC_SIGN::findIn) + .ifPresent(builder::predefinedAppImageSigned); + + PREDEFINED_RUNTIME_IMAGE.findIn(options) + .map(MacBundle::new) + .filter(MacBundle::isValid) + .map(MacBundle::isSigned) + .ifPresent(builder::predefinedAppImageSigned); + + return builder; + } + + private static void rethrowIfNotExpiredCertificateException(Result result) { + final var ex = result.firstError().orElseThrow(); + + if (ex instanceof ExpiredCertificateException) { + return; + } + + if (ex instanceof ExceptionBox box) { + if (box.getCause() instanceof Exception cause) { + rethrowIfNotExpiredCertificateException(Result.ofError(cause)); + } + } + + rethrowUnchecked(ex); + } + + private static SigningIdentityBuilder createSigningIdentityBuilder(Options options) { + final var builder = new SigningIdentityBuilder(); + MAC_SIGNING_KEYCHAIN.findIn(options).map(Path::toString).ifPresent(builder::keychain); + return builder; + } + + private static MacFileAssociation createMacFa(Options options, FileAssociation fa) { + + final var builder = new MacFileAssociationBuilder(); + + StandardFaOption.MAC_CFBUNDLETYPEROLE.ifPresentIn(options, builder::cfBundleTypeRole); + StandardFaOption.MAC_LSHANDLERRANK.ifPresentIn(options, builder::lsHandlerRank); + StandardFaOption.MAC_NSSTORETYPEKEY.ifPresentIn(options, builder::nsPersistentStoreTypeKey); + StandardFaOption.MAC_NSDOCUMENTCLASS.ifPresentIn(options, builder::nsDocumentClass); + StandardFaOption.MAC_LSTYPEISPACKAGE.ifPresentIn(options, builder::lsTypeIsPackage); + StandardFaOption.MAC_LSDOCINPLACE.ifPresentIn(options, builder::lsSupportsOpeningDocumentsInPlace); + StandardFaOption.MAC_UIDOCBROWSER.ifPresentIn(options, builder::uiSupportsDocumentBrowser); + StandardFaOption.MAC_NSEXPORTABLETYPES.ifPresentIn(options, builder::nsExportableTypes); + StandardFaOption.MAC_UTTYPECONFORMSTO.ifPresentIn(options, builder::utTypeConformsTo); + + return builder.create(fa); + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java deleted file mode 100644 index 72c33ef6475..00000000000 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.jpackage.internal; - -import static jdk.jpackage.internal.BundlerParamInfo.createBooleanBundlerParam; -import static jdk.jpackage.internal.BundlerParamInfo.createPathBundlerParam; -import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; -import static jdk.jpackage.internal.FromParams.createApplicationBuilder; -import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; -import static jdk.jpackage.internal.FromParams.createPackageBuilder; -import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; -import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; -import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasJliLib; -import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasNoBinDir; -import static jdk.jpackage.internal.StandardBundlerParam.DMG_CONTENT; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; -import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; -import static jdk.jpackage.internal.model.MacPackage.RUNTIME_BUNDLE_LAYOUT; -import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; -import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.Callable; -import java.util.function.Predicate; -import jdk.jpackage.internal.ApplicationBuilder.MainLauncherStartupInfo; -import jdk.jpackage.internal.SigningIdentityBuilder.ExpiredCertificateException; -import jdk.jpackage.internal.SigningIdentityBuilder.StandardCertificateSelector; -import jdk.jpackage.internal.model.ApplicationLaunchers; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.FileAssociation; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.MacApplication; -import jdk.jpackage.internal.model.MacDmgPackage; -import jdk.jpackage.internal.model.MacFileAssociation; -import jdk.jpackage.internal.model.MacLauncher; -import jdk.jpackage.internal.model.MacPackage; -import jdk.jpackage.internal.model.MacPkgPackage; -import jdk.jpackage.internal.model.PackageType; -import jdk.jpackage.internal.model.RuntimeLayout; -import jdk.jpackage.internal.util.function.ExceptionBox; - - -final class MacFromParams { - - private static MacApplication createMacApplication( - Map params) throws ConfigException, IOException { - - final var predefinedRuntimeLayout = PREDEFINED_RUNTIME_IMAGE.findIn(params) - .map(MacPackage::guessRuntimeLayout); - - if (predefinedRuntimeLayout.isPresent()) { - validateRuntimeHasJliLib(predefinedRuntimeLayout.orElseThrow()); - if (APP_STORE.findIn(params).orElse(false)) { - validateRuntimeHasNoBinDir(predefinedRuntimeLayout.orElseThrow()); - } - } - - final var launcherFromParams = new LauncherFromParams(Optional.of(MacFromParams::createMacFa)); - - final var superAppBuilder = createApplicationBuilder(params, toFunction(launcherParams -> { - var launcher = launcherFromParams.create(launcherParams); - return MacLauncher.create(launcher); - }), (MacLauncher _, Launcher launcher) -> { - return MacLauncher.create(launcher); - }, APPLICATION_LAYOUT, RUNTIME_BUNDLE_LAYOUT, predefinedRuntimeLayout.map(RuntimeLayout::unresolve)); - - if (hasPredefinedAppImage(params)) { - // Set the main launcher start up info. - // AppImageFile assumes the main launcher start up info is available when - // it is constructed from Application instance. - // This happens when jpackage signs predefined app image. - final var mainLauncherStartupInfo = new MainLauncherStartupInfo(superAppBuilder.mainLauncherClassName().orElseThrow()); - final var launchers = superAppBuilder.launchers().orElseThrow(); - final var mainLauncher = ApplicationBuilder.overrideLauncherStartupInfo(launchers.mainLauncher(), mainLauncherStartupInfo); - superAppBuilder.launchers(new ApplicationLaunchers(MacLauncher.create(mainLauncher), launchers.additionalLaunchers())); - } - - final var app = superAppBuilder.create(); - - final var appBuilder = new MacApplicationBuilder(app); - - if (hasPredefinedAppImage(params)) { - appBuilder.externalInfoPlistFile(PREDEFINED_APP_IMAGE.findIn(params).map(MacBundle::new).orElseThrow().infoPlistFile()); - } - - ICON.copyInto(params, appBuilder::icon); - MAC_CF_BUNDLE_NAME.copyInto(params, appBuilder::bundleName); - MAC_CF_BUNDLE_IDENTIFIER.copyInto(params, appBuilder::bundleIdentifier); - APP_CATEGORY.copyInto(params, appBuilder::category); - - final boolean sign; - final boolean appStore; - - if (hasPredefinedAppImage(params) && PACKAGE_TYPE.findIn(params).filter(Predicate.isEqual("app-image")).isEmpty()) { - final var appImageFileExtras = new MacAppImageFileExtras(superAppBuilder.externalApplication().orElseThrow()); - sign = appImageFileExtras.signed(); - appStore = appImageFileExtras.appStore(); - } else { - sign = SIGN_BUNDLE.findIn(params).orElse(false); - appStore = APP_STORE.findIn(params).orElse(false); - } - - appBuilder.appStore(appStore); - - if (sign) { - final var signingIdentityBuilder = createSigningIdentityBuilder(params); - APP_IMAGE_SIGN_IDENTITY.copyInto(params, signingIdentityBuilder::signingIdentity); - SIGNING_KEY_USER.findIn(params).ifPresent(userName -> { - final StandardCertificateSelector domain; - if (appStore) { - domain = StandardCertificateSelector.APP_STORE_APP_IMAGE; - } else { - domain = StandardCertificateSelector.APP_IMAGE; - } - - signingIdentityBuilder.certificateSelector(StandardCertificateSelector.create(userName, domain)); - }); - - final var signingBuilder = new AppImageSigningConfigBuilder(signingIdentityBuilder); - if (appStore) { - signingBuilder.entitlementsResourceName("sandbox.plist"); - } - - final var bundleIdentifier = appBuilder.create().bundleIdentifier(); - app.mainLauncher().flatMap(Launcher::startupInfo).ifPresentOrElse( - signingBuilder::signingIdentifierPrefix, - () -> { - // Runtime installer does not have main launcher, so use - // 'bundleIdentifier' as prefix by default. - signingBuilder.signingIdentifierPrefix( - bundleIdentifier + "."); - }); - SIGN_IDENTIFIER_PREFIX.copyInto(params, signingBuilder::signingIdentifierPrefix); - - ENTITLEMENTS.copyInto(params, signingBuilder::entitlements); - - appBuilder.signingBuilder(signingBuilder); - } - - return appBuilder.create(); - } - - private static MacPackageBuilder createMacPackageBuilder( - Map params, MacApplication app, - PackageType type) throws ConfigException { - final var builder = new MacPackageBuilder(createPackageBuilder(params, app, type)); - - PREDEFINED_APP_IMAGE_FILE.findIn(params) - .map(MacAppImageFileExtras::new) - .map(MacAppImageFileExtras::signed) - .ifPresent(builder::predefinedAppImageSigned); - - PREDEFINED_RUNTIME_IMAGE.findIn(params) - .map(MacBundle::new) - .filter(MacBundle::isValid) - .map(MacBundle::isSigned) - .ifPresent(builder::predefinedAppImageSigned); - - return builder; - } - - private static MacDmgPackage createMacDmgPackage( - Map params) throws ConfigException, IOException { - - final var app = APPLICATION.fetchFrom(params); - - final var superPkgBuilder = createMacPackageBuilder(params, app, MAC_DMG); - - final var pkgBuilder = new MacDmgPackageBuilder(superPkgBuilder); - - DMG_CONTENT.copyInto(params, pkgBuilder::dmgContent); - - return pkgBuilder.create(); - } - - private record WithExpiredCertificateException(Optional obj, Optional certEx) { - WithExpiredCertificateException { - if (obj.isEmpty() == certEx.isEmpty()) { - throw new IllegalArgumentException(); - } - } - - static WithExpiredCertificateException of(Callable callable) { - try { - return new WithExpiredCertificateException<>(Optional.of(callable.call()), Optional.empty()); - } catch (ExpiredCertificateException ex) { - return new WithExpiredCertificateException<>(Optional.empty(), Optional.of(ex)); - } catch (ExceptionBox ex) { - if (ex.getCause() instanceof ExpiredCertificateException certEx) { - return new WithExpiredCertificateException<>(Optional.empty(), Optional.of(certEx)); - } - throw ex; - } catch (RuntimeException ex) { - throw ex; - } catch (Throwable t) { - throw ExceptionBox.rethrowUnchecked(t); - } - } - } - - private static MacPkgPackage createMacPkgPackage( - Map params) throws ConfigException, IOException { - - // This is over complicated to make "MacSignTest.testExpiredCertificate" test pass. - - final boolean sign = SIGN_BUNDLE.findIn(params).orElse(false); - final boolean appStore = APP_STORE.findIn(params).orElse(false); - - final var appOrExpiredCertEx = WithExpiredCertificateException.of(() -> { - return APPLICATION.fetchFrom(params); - }); - - final Optional pkgBuilder; - if (appOrExpiredCertEx.obj().isPresent()) { - final var superPkgBuilder = createMacPackageBuilder(params, appOrExpiredCertEx.obj().orElseThrow(), MAC_PKG); - pkgBuilder = Optional.of(new MacPkgPackageBuilder(superPkgBuilder)); - } else { - pkgBuilder = Optional.empty(); - } - - if (sign) { - final var signingIdentityBuilder = createSigningIdentityBuilder(params); - INSTALLER_SIGN_IDENTITY.copyInto(params, signingIdentityBuilder::signingIdentity); - SIGNING_KEY_USER.findIn(params).ifPresent(userName -> { - final StandardCertificateSelector domain; - if (appStore) { - domain = StandardCertificateSelector.APP_STORE_PKG_INSTALLER; - } else { - domain = StandardCertificateSelector.PKG_INSTALLER; - } - - signingIdentityBuilder.certificateSelector(StandardCertificateSelector.create(userName, domain)); - }); - - if (pkgBuilder.isPresent()) { - pkgBuilder.orElseThrow().signingBuilder(signingIdentityBuilder); - } else { - final var expiredPkgCert = WithExpiredCertificateException.of(() -> { - return signingIdentityBuilder.create(); - }).certEx(); - expiredPkgCert.map(ConfigException::getMessage).ifPresent(Log::error); - throw appOrExpiredCertEx.certEx().orElseThrow(); - } - } - - return pkgBuilder.orElseThrow().create(); - } - - private static SigningIdentityBuilder createSigningIdentityBuilder(Map params) { - final var builder = new SigningIdentityBuilder(); - SIGNING_KEYCHAIN.copyInto(params, builder::keychain); - return builder; - } - - private static MacFileAssociation createMacFa(FileAssociation fa, Map params) { - - final var builder = new MacFileAssociationBuilder(); - - FA_MAC_CFBUNDLETYPEROLE.copyInto(params, builder::cfBundleTypeRole); - FA_MAC_LSHANDLERRANK.copyInto(params, builder::lsHandlerRank); - FA_MAC_NSSTORETYPEKEY.copyInto(params, builder::nsPersistentStoreTypeKey); - FA_MAC_NSDOCUMENTCLASS.copyInto(params, builder::nsDocumentClass); - FA_MAC_LSTYPEISPACKAGE.copyInto(params, builder::lsTypeIsPackage); - FA_MAC_LSDOCINPLACE.copyInto(params, builder::lsSupportsOpeningDocumentsInPlace); - FA_MAC_UIDOCBROWSER.copyInto(params, builder::uiSupportsDocumentBrowser); - FA_MAC_NSEXPORTABLETYPES.copyInto(params, builder::nsExportableTypes); - FA_MAC_UTTYPECONFORMSTO.copyInto(params, builder::utTypeConformsTo); - - return toFunction(builder::create).apply(fa); - } - - static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( - MacFromParams::createMacApplication); - - static final BundlerParamInfo DMG_PACKAGE = createPackageBundlerParam( - MacFromParams::createMacDmgPackage); - - static final BundlerParamInfo PKG_PACKAGE = createPackageBundlerParam( - MacFromParams::createMacPkgPackage); - - private static final BundlerParamInfo MAC_CF_BUNDLE_NAME = createStringBundlerParam( - Arguments.CLIOptions.MAC_BUNDLE_NAME.getId()); - - private static final BundlerParamInfo APP_CATEGORY = createStringBundlerParam( - Arguments.CLIOptions.MAC_CATEGORY.getId()); - - private static final BundlerParamInfo ENTITLEMENTS = createPathBundlerParam( - Arguments.CLIOptions.MAC_ENTITLEMENTS.getId()); - - private static final BundlerParamInfo MAC_CF_BUNDLE_IDENTIFIER = createStringBundlerParam( - Arguments.CLIOptions.MAC_BUNDLE_IDENTIFIER.getId()); - - private static final BundlerParamInfo SIGN_IDENTIFIER_PREFIX = createStringBundlerParam( - Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId()); - - private static final BundlerParamInfo APP_IMAGE_SIGN_IDENTITY = createStringBundlerParam( - Arguments.CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId()); - - private static final BundlerParamInfo INSTALLER_SIGN_IDENTITY = createStringBundlerParam( - Arguments.CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getId()); - - private static final BundlerParamInfo SIGNING_KEY_USER = createStringBundlerParam( - Arguments.CLIOptions.MAC_SIGNING_KEY_NAME.getId()); - - private static final BundlerParamInfo SIGNING_KEYCHAIN = createStringBundlerParam( - Arguments.CLIOptions.MAC_SIGNING_KEYCHAIN.getId()); - - private static final BundlerParamInfo PACKAGE_TYPE = createStringBundlerParam( - Arguments.CLIOptions.PACKAGE_TYPE.getId()); - - private static final BundlerParamInfo APP_STORE = createBooleanBundlerParam( - Arguments.CLIOptions.MAC_APP_STORE.getId()); - - private static final BundlerParamInfo FA_MAC_CFBUNDLETYPEROLE = createStringBundlerParam( - Arguments.MAC_CFBUNDLETYPEROLE); - - private static final BundlerParamInfo FA_MAC_LSHANDLERRANK = createStringBundlerParam( - Arguments.MAC_LSHANDLERRANK); - - private static final BundlerParamInfo FA_MAC_NSSTORETYPEKEY = createStringBundlerParam( - Arguments.MAC_NSSTORETYPEKEY); - - private static final BundlerParamInfo FA_MAC_NSDOCUMENTCLASS = createStringBundlerParam( - Arguments.MAC_NSDOCUMENTCLASS); - - private static final BundlerParamInfo FA_MAC_LSTYPEISPACKAGE = createBooleanBundlerParam( - Arguments.MAC_LSTYPEISPACKAGE); - - private static final BundlerParamInfo FA_MAC_LSDOCINPLACE = createBooleanBundlerParam( - Arguments.MAC_LSDOCINPLACE); - - private static final BundlerParamInfo FA_MAC_UIDOCBROWSER = createBooleanBundlerParam( - Arguments.MAC_UIDOCBROWSER); - - @SuppressWarnings("unchecked") - private static final BundlerParamInfo> FA_MAC_NSEXPORTABLETYPES = - new BundlerParamInfo<>( - Arguments.MAC_NSEXPORTABLETYPES, - (Class>) (Object) List.class, - null, - (s, p) -> Arrays.asList(s.split("(,|\\s)+")) - ); - - @SuppressWarnings("unchecked") - private static final BundlerParamInfo> FA_MAC_UTTYPECONFORMSTO = - new BundlerParamInfo<>( - Arguments.MAC_UTTYPECONFORMSTO, - (Class>) (Object) List.class, - null, - (s, p) -> Arrays.asList(s.split("(,|\\s)+")) - ); -} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java index 9576f6a6a99..e19f234d0d6 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java @@ -29,7 +29,6 @@ import static jdk.jpackage.internal.MacPackagingPipeline.LayoutUtils.packagerLay import java.nio.file.Files; import java.util.Objects; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacPackage; import jdk.jpackage.internal.model.MacPackageMixin; @@ -49,7 +48,7 @@ final class MacPackageBuilder { return pkgBuilder; } - MacPackage create() throws ConfigException { + MacPackage create() { final var app = (MacApplication)pkgBuilder.app(); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 6e63b73674e..53f297282ba 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -75,7 +75,6 @@ import jdk.jpackage.internal.model.MacFileAssociation; import jdk.jpackage.internal.model.MacPackage; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackageType; -import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; @@ -225,10 +224,12 @@ final class MacPackagingPipeline { if (!app.sign()) { throw new IllegalArgumentException(); } - return toSupplier(() -> { - return new PackageBuilder(app, SignAppImagePackageType.VALUE).predefinedAppImage( - Objects.requireNonNull(env.appImageDir())).installDir(Path.of("/foo")).create(); - }).get(); + return new PackageBuilder( + app, + SignAppImagePackageType.VALUE + ).predefinedAppImage( + Objects.requireNonNull(env.appImageDir()) + ).installDir(Path.of("/foo")).create(); } static final class LayoutUtils { @@ -268,7 +269,7 @@ final class MacPackagingPipeline { static AppImageTaskAction withBundleLayout(AppImageTaskAction action) { return new AppImageTaskAction<>() { @Override - public void execute(AppImageBuildEnv env) throws IOException, PackagerException { + public void execute(AppImageBuildEnv env) throws IOException { if (!env.envLayout().runtimeDirectory().getName(0).equals(Path.of("Contents"))) { env = LayoutUtils.fromPackagerLayout(env); } @@ -364,12 +365,21 @@ final class MacPackagingPipeline { final var app = env.app(); + // If the embedded runtime contains executable(s) in the "bin" + // subdirectory, we should use the standalone runtime info plist + // template. Otherwise, the user may be unable to run the "java" + // or other executables in the "bin" subdirectory of the embedded + // runtime. + final var useRuntimeInfoPlist = app.isRuntime() || + app.runtimeBuilder().orElseThrow().withNativeCommands() || + Files.isDirectory(env.resolvedLayout().runtimeDirectory().resolve("bin")); + Map data = new HashMap<>(); data.put("CF_BUNDLE_IDENTIFIER", app.bundleIdentifier()); data.put("CF_BUNDLE_NAME", app.bundleName()); data.put("CF_BUNDLE_VERSION", app.version()); data.put("CF_BUNDLE_SHORT_VERSION_STRING", app.shortVersion().toString()); - if (app.isRuntime()) { + if (useRuntimeInfoPlist) { data.put("CF_BUNDLE_VENDOR", app.vendor()); } @@ -377,12 +387,18 @@ final class MacPackagingPipeline { final String publicName; final String category; - if (app.isRuntime()) { + if (useRuntimeInfoPlist) { template = "Runtime-Info.plist.template"; + } else { + template = "ApplicationRuntime-Info.plist.template"; + } + + // Public name and category should be based on standalone runtime vs + // embedded runtime. + if (app.isRuntime()) { publicName = "Info.plist"; category = "resource.runtime-info-plist"; } else { - template = "ApplicationRuntime-Info.plist.template"; publicName = "Runtime-Info.plist"; category = "resource.app-runtime-info-plist"; } @@ -595,11 +611,20 @@ final class MacPackagingPipeline { } @Override - public void execute(TaskAction taskAction) throws IOException, PackagerException { + public void execute(TaskAction taskAction) throws IOException { delegate.execute(taskAction); } } + private static final ApplicationLayout MAC_APPLICATION_LAYOUT = ApplicationLayout.build() + .launchersDirectory("Contents/MacOS") + .appDirectory("Contents/app") + .runtimeDirectory("Contents/runtime/Contents/Home") + .desktopIntegrationDirectory("Contents/Resources") + .appModsDirectory("Contents/app/mods") + .contentDirectory("Contents") + .create(); + static final MacApplicationLayout APPLICATION_LAYOUT = MacApplicationLayout.create( - ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT, Path.of("Contents/runtime")); + MAC_APPLICATION_LAYOUT, Path.of("Contents/runtime")); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java deleted file mode 100644 index e827f238db3..00000000000 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2014, 2025, 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 jdk.jpackage.internal; - -import java.nio.file.Path; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.MacPkgPackage; -import jdk.jpackage.internal.model.PackagerException; - -public class MacPkgBundler extends MacBaseInstallerBundler { - - @Override - public String getName() { - return I18N.getString("pkg.bundler.name"); - } - - @Override - public String getID() { - return "pkg"; - } - - @Override - public boolean validate(Map params) - throws ConfigException { - try { - Objects.requireNonNull(params); - - final var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); - - // run basic validation to ensure requirements are met - // we are not interested in return code, only possible exception - validateAppImageAndBundeler(params); - - // hdiutil is always available so there's no need - // to test for availability. - - return true; - } catch (RuntimeException re) { - if (re.getCause() instanceof ConfigException) { - throw (ConfigException) re.getCause(); - } else { - throw new ConfigException(re); - } - } - } - - @Override - public Path execute(Map params, - Path outputParentDir) throws PackagerException { - - var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); - - Log.verbose(I18N.format("message.building-pkg", pkg.app().name())); - - return Packager.build().outputDir(outputParentDir) - .pkg(pkg) - .env(MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params)) - .pipelineBuilderMutatorFactory((env, _, outputDir) -> { - return new MacPkgPackager(env, pkg, outputDir); - }).execute(MacPackagingPipeline.build(Optional.of(pkg))); - } - - @Override - public boolean supported(boolean runtimeInstaller) { - return true; - } - - @Override - public boolean isDefault() { - return false; - } - -} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java index 663b8b16265..b81340354e1 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackageBuilder.java @@ -26,7 +26,6 @@ package jdk.jpackage.internal; import java.util.Objects; import java.util.Optional; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.MacPkgPackageMixin; import jdk.jpackage.internal.model.PkgSigningConfig; @@ -42,20 +41,16 @@ final class MacPkgPackageBuilder { return this; } - MacPkgPackage create() throws ConfigException { + MacPkgPackage create() { var pkg = MacPkgPackage.create(pkgBuilder.create(), new MacPkgPackageMixin.Stub(createSigningConfig())); validatePredefinedAppImage(pkg); return pkg; } - private Optional createSigningConfig() throws ConfigException { - if (signingBuilder != null) { - return signingBuilder.create().map(cfg -> { - return new PkgSigningConfig.Stub(cfg.identity(), cfg.keychain().map(Keychain::name)); - }); - } else { - return Optional.empty(); - } + private Optional createSigningConfig() { + return Optional.ofNullable(signingBuilder).flatMap(SigningIdentityBuilder::create).map(cfg -> { + return new PkgSigningConfig.Stub(cfg.identity(), cfg.keychain().map(Keychain::name)); + }); } private static void validatePredefinedAppImage(MacPkgPackage pkg) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java index e7ef6a23fa7..cfab12cbcba 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java @@ -30,12 +30,11 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.function.Predicate; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.RuntimeLayout; final class MacRuntimeValidator { - static void validateRuntimeHasJliLib(RuntimeLayout runtimeLayout) throws ConfigException { + static void validateRuntimeHasJliLib(RuntimeLayout runtimeLayout) { final var jliName = Path.of("libjli.dylib"); try (var walk = Files.walk(runtimeLayout.runtimeDirectory().resolve("lib"))) { if (walk.map(Path::getFileName).anyMatch(Predicate.isEqual(jliName))) { @@ -51,7 +50,7 @@ final class MacRuntimeValidator { runtimeLayout.unresolve().runtimeDirectory().resolve("lib/**").resolve(jliName)).create(); } - static void validateRuntimeHasNoBinDir(RuntimeLayout runtimeLayout) throws ConfigException { + static void validateRuntimeHasNoBinDir(RuntimeLayout runtimeLayout) { if (Files.isDirectory(runtimeLayout.runtimeDirectory().resolve("bin"))) { throw I18N.buildConfigException() .message("error.invalid-runtime-image-bin-dir", runtimeLayout.rootDirectory()) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityBuilder.java index bf8f1519fe1..9a57ce1e697 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/SigningIdentityBuilder.java @@ -82,7 +82,7 @@ final class SigningIdentityBuilder { return this; } - Optional create() throws ConfigException { + Optional create() { if (signingIdentity == null && certificateSelector == null) { return Optional.empty(); } else { @@ -90,11 +90,11 @@ final class SigningIdentityBuilder { } } - private Optional validatedKeychain() throws ConfigException { + private Optional validatedKeychain() { return Optional.ofNullable(keychain).map(Keychain::new); } - private SigningIdentity validatedSigningIdentity() throws ConfigException { + private SigningIdentity validatedSigningIdentity() { if (signingIdentity != null) { return new SigningIdentityImpl(signingIdentity); } @@ -142,7 +142,7 @@ final class SigningIdentityBuilder { } private static X509Certificate selectSigningIdentity(List certs, - CertificateSelector certificateSelector, Optional keychain) throws ConfigException { + CertificateSelector certificateSelector, Optional keychain) { Objects.requireNonNull(certificateSelector); Objects.requireNonNull(keychain); switch (certs.size()) { @@ -156,9 +156,10 @@ final class SigningIdentityBuilder { return certs.getFirst(); } default -> { - Log.error(I18N.format("error.multiple.certs.found", certificateSelector.signingIdentities().getFirst(), - keychain.map(Keychain::name).orElse(""))); - return certs.getFirst(); + throw I18N.buildConfigException("error.multiple.certs.found", + certificateSelector.signingIdentities().getFirst(), + keychain.map(Keychain::name).orElse("") + ).create(); } } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java index 04ab7042ac5..cfe10e8a012 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacApplication.java @@ -25,13 +25,18 @@ package jdk.jpackage.internal.model; import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toUnmodifiableMap; +import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_APP_STORE; +import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_MAIN_CLASS; +import static jdk.jpackage.internal.cli.StandardAppImageFileOption.MAC_SIGNED; import java.nio.file.Path; import java.util.Map; +import java.util.Optional; import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.Stream; +import jdk.jpackage.internal.cli.OptionValue; import jdk.jpackage.internal.util.CompositeProxy; public interface MacApplication extends Application, MacApplicationMixin { @@ -76,7 +81,14 @@ public interface MacApplication extends Application, MacApplicationMixin { @Override default Map extraAppImageFileData() { - return Stream.of(ExtraAppImageFileField.values()).collect(toMap(ExtraAppImageFileField::fieldName, x -> x.asString(this))); + return Stream.of(ExtraAppImageFileField.values()).map(field -> { + return field.findStringValue(this).map(value -> { + return Map.entry(field.fieldName(), value); + }); + }) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue)); } public static MacApplication create(Application app, MacApplicationMixin mixin) { @@ -84,23 +96,31 @@ public interface MacApplication extends Application, MacApplicationMixin { } public enum ExtraAppImageFileField { - SIGNED("signed", app -> Boolean.toString(app.sign())), - APP_STORE("app-store", app -> Boolean.toString(app.appStore())); + SIGNED(MAC_SIGNED, app -> { + return Optional.of(Boolean.toString(app.sign())); + }), + APP_STORE(MAC_APP_STORE, app -> { + return Optional.of(Boolean.toString(app.appStore())); + }), + APP_CLASS(MAC_MAIN_CLASS, app -> { + return app.mainLauncher().flatMap(Launcher::startupInfo).map(LauncherStartupInfo::qualifiedClassName); + }), + ; - ExtraAppImageFileField(String fieldName, Function getter) { - this.fieldName = fieldName; + ExtraAppImageFileField(OptionValue option, Function> getter) { + this.fieldName = option.getName(); this.getter = getter; } - public String fieldName() { + String fieldName() { return fieldName; } - String asString(MacApplication app) { + Optional findStringValue(MacApplication app) { return getter.apply(app); } private final String fieldName; - private final Function getter; + private final Function> getter; } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index 58c3bbbc025..d01297aa814 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -23,26 +23,17 @@ # questions. # # - -app.bundler.name=Mac Application Image -store.bundler.name=Mac App Store Ready Bundler -dmg.bundler.name=Mac DMG Package -pkg.bundler.name=Mac PKG Package - error.invalid-cfbundle-version.advice=Set a compatible 'app-version' value. Valid versions are one to three integers separated by dots. error.explicit-sign-no-cert=Signature explicitly requested but no signing certificate found error.explicit-sign-no-cert.advice=Specify a valid mac-signing-key-user-name and mac-signing-keychain -error.must-sign-app-store=Mac App Store apps must be signed, and signing has been disabled by bundler configuration -error.must-sign-app-store.advice=Use --mac-sign option with appropriate user-name and keychain -error.certificate.expired=Error: Certificate expired {0} +error.certificate.expired=Certificate expired {0} error.cert.not.found=No certificate found matching [{0}] using keychain [{1}] -error.multiple.certs.found=WARNING: Multiple certificates found matching [{0}] using keychain [{1}], using first one -error.app-image.mac-sign.required=Error: --mac-sign option is required with predefined application image and with type [app-image] -error.tool.failed.with.output=Error: "{0}" failed with following output: +error.multiple.certs.found=Multiple certificates matching name [{0}] found in keychain [{1}] +error.app-image.mac-sign.required=--mac-sign option is required with predefined application image and with type [app-image] +error.tool.failed.with.output="{0}" failed with following output: error.invalid-runtime-image-missing-file=Runtime image "{0}" is missing "{1}" file error.invalid-runtime-image-bin-dir=Runtime image "{0}" should not contain "bin" folder error.invalid-runtime-image-bin-dir.advice=Use --strip-native-commands jlink option when generating runtime image used with {0} option -resource.bundle-config-file=Bundle config file resource.app-info-plist=Application Info.plist resource.app-runtime-info-plist=Embedded Java Runtime Info.plist resource.runtime-info-plist=Java Runtime Info.plist @@ -60,21 +51,15 @@ resource.pkg-background-image=pkg background image resource.pkg-pdf=project definition file resource.launchd-plist-file=launchd plist file - message.bundle-name-too-long-warning={0} is set to ''{1}'', which is longer than 16 characters. For a better Mac experience consider shortening it. message.preparing-info-plist=Preparing Info.plist: {0}. message.icon-not-icns= The specified icon "{0}" is not an ICNS file and will not be used. The default icon will be used in it's place. message.version-string-too-many-components='app-version' may have between 1 and 3 numbers: 1, 1.2, 1.2.3. message.version-string-first-number-not-zero=The first number in an app-version cannot be zero or negative. -message.creating-association-with-null-extension=Creating association with null extension. -message.ignoring.symlink=Warning: codesign is skipping the symlink {0}. -message.already.signed=File already signed: {0}. -message.keychain.error=Error: unable to get keychain list. -message.building-bundle=Building Mac App Store Package for {0}. -message.invalid-identifier=invalid mac bundle identifier [{0}]. +message.keychain.error=Unable to get keychain list. +message.invalid-identifier=Invalid mac bundle identifier [{0}]. message.invalid-identifier.advice=specify identifier with "--mac-package-identifier". message.building-dmg=Building DMG package for {0}. -message.running-script=Running shell script on application image [{0}]. message.preparing-dmg-setup=Preparing dmg setup: {0}. message.creating-dmg-file=Creating DMG file: {0}. message.dmg-cannot-be-overwritten=Dmg file exists [{0}] and can not be removed. diff --git a/src/jdk.jpackage/macosx/classes/module-info.java.extra b/src/jdk.jpackage/macosx/classes/module-info.java.extra index 1496167cd4a..e6202dd1156 100644 --- a/src/jdk.jpackage/macosx/classes/module-info.java.extra +++ b/src/jdk.jpackage/macosx/classes/module-info.java.extra @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,5 @@ * questions. */ -provides jdk.jpackage.internal.Bundler with - jdk.jpackage.internal.MacAppBundler, - jdk.jpackage.internal.MacDmgBundler, - jdk.jpackage.internal.MacPkgBundler; - +provides jdk.jpackage.internal.cli.CliBundlingEnvironment with + jdk.jpackage.internal.MacBundlingEnvironment; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java deleted file mode 100644 index 93d037c6a45..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2018, 2023, 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 jdk.jpackage.internal; - -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import java.util.List; -import java.util.Optional; - -import jdk.internal.util.OperatingSystem; - -import jdk.jpackage.internal.Arguments.CLIOptions; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; - -/* - * AddLauncherArguments - * - * Processes a add-launcher properties file to create the Map of - * bundle params applicable to the add-launcher: - * - * BundlerParams p = (new AddLauncherArguments(file)).getLauncherMap(); - * - * A add-launcher is another executable program generated by either the - * create-app-image mode or the create-installer mode. - * The add-launcher may be the same program with different configuration, - * or a completely different program created from the same files. - * - * There may be multiple add-launchers, each created by using the - * command line arg "--add-launcher - * - * The add-launcher properties file may have any of: - * - * appVersion - * description - * module - * main-jar - * main-class - * icon - * arguments - * java-options - * launcher-as-service - * win-console - * win-shortcut - * win-menu - * linux-app-category - * linux-shortcut - * - */ -class AddLauncherArguments { - - private final String name; - private final String filename; - private Map allArgs; - private Map bundleParams; - - AddLauncherArguments(String name, String filename) { - this.name = name; - this.filename = filename; - } - - private void initLauncherMap() { - if (bundleParams != null) { - return; - } - - allArgs = Arguments.getPropertiesFromFile(filename); - allArgs.put(CLIOptions.NAME.getId(), name); - - bundleParams = new HashMap<>(); - String mainJar = getOptionValue(CLIOptions.MAIN_JAR); - String mainClass = getOptionValue(CLIOptions.APPCLASS); - String module = getOptionValue(CLIOptions.MODULE); - - if (module != null && mainClass != null) { - Arguments.putUnlessNull(bundleParams, CLIOptions.MODULE.getId(), - module + "/" + mainClass); - } else if (module != null) { - Arguments.putUnlessNull(bundleParams, CLIOptions.MODULE.getId(), - module); - } else { - Arguments.putUnlessNull(bundleParams, CLIOptions.MAIN_JAR.getId(), - mainJar); - Arguments.putUnlessNull(bundleParams, CLIOptions.APPCLASS.getId(), - mainClass); - } - - Arguments.putUnlessNull(bundleParams, CLIOptions.NAME.getId(), - getOptionValue(CLIOptions.NAME)); - - Arguments.putUnlessNull(bundleParams, CLIOptions.VERSION.getId(), - getOptionValue(CLIOptions.VERSION)); - - Arguments.putUnlessNull(bundleParams, CLIOptions.DESCRIPTION.getId(), - getOptionValue(CLIOptions.DESCRIPTION)); - - Arguments.putUnlessNull(bundleParams, CLIOptions.RELEASE.getId(), - getOptionValue(CLIOptions.RELEASE)); - - Arguments.putUnlessNull(bundleParams, CLIOptions.ICON.getId(), - Optional.ofNullable(getOptionValue(CLIOptions.ICON)).map( - Path::of).orElse(null)); - - Arguments.putUnlessNull(bundleParams, - CLIOptions.LAUNCHER_AS_SERVICE.getId(), getOptionValue( - CLIOptions.LAUNCHER_AS_SERVICE)); - - if (OperatingSystem.isWindows()) { - Arguments.putUnlessNull(bundleParams, - CLIOptions.WIN_CONSOLE_HINT.getId(), - getOptionValue(CLIOptions.WIN_CONSOLE_HINT)); - Arguments.putUnlessNull(bundleParams, CLIOptions.WIN_SHORTCUT_HINT.getId(), - getOptionValue(CLIOptions.WIN_SHORTCUT_HINT)); - Arguments.putUnlessNull(bundleParams, CLIOptions.WIN_MENU_HINT.getId(), - getOptionValue(CLIOptions.WIN_MENU_HINT)); - } - - if (OperatingSystem.isLinux()) { - Arguments.putUnlessNull(bundleParams, CLIOptions.LINUX_CATEGORY.getId(), - getOptionValue(CLIOptions.LINUX_CATEGORY)); - Arguments.putUnlessNull(bundleParams, CLIOptions.LINUX_SHORTCUT_HINT.getId(), - getOptionValue(CLIOptions.LINUX_SHORTCUT_HINT)); - } - - // "arguments" and "java-options" even if value is null: - if (allArgs.containsKey(CLIOptions.ARGUMENTS.getId())) { - String argumentStr = getOptionValue(CLIOptions.ARGUMENTS); - bundleParams.put(CLIOptions.ARGUMENTS.getId(), - Arguments.getArgumentList(argumentStr)); - } - - if (allArgs.containsKey(CLIOptions.JAVA_OPTIONS.getId())) { - String jvmargsStr = getOptionValue(CLIOptions.JAVA_OPTIONS); - bundleParams.put(CLIOptions.JAVA_OPTIONS.getId(), - Arguments.getArgumentList(jvmargsStr)); - } - } - - private String getOptionValue(CLIOptions option) { - if (option == null || allArgs == null) { - return null; - } - - String id = option.getId(); - - if (allArgs.containsKey(id)) { - return allArgs.get(id); - } - - return null; - } - - Map getLauncherMap() { - initLauncherMap(); - return bundleParams; - } - - static Map merge( - Map original, - Map additional, String... exclude) { - Map tmp = new HashMap<>(original); - List.of(exclude).forEach(tmp::remove); - - // remove LauncherData from map so it will be re-computed - tmp.remove(LAUNCHER_DATA.getID()); - // remove "application-name" so it will be re-computed - tmp.remove(APP_NAME.getID()); - - if (additional.containsKey(CLIOptions.MODULE.getId())) { - tmp.remove(CLIOptions.MAIN_JAR.getId()); - tmp.remove(CLIOptions.APPCLASS.getId()); - } else if (additional.containsKey(CLIOptions.MAIN_JAR.getId())) { - tmp.remove(CLIOptions.MODULE.getId()); - } - if (additional.containsKey(CLIOptions.ARGUMENTS.getId())) { - // if add launcher properties file contains "arguments", even with - // null value, disregard the "arguments" from command line - tmp.remove(CLIOptions.ARGUMENTS.getId()); - } - if (additional.containsKey(CLIOptions.JAVA_OPTIONS.getId())) { - // same thing for java-options - tmp.remove(CLIOptions.JAVA_OPTIONS.getId()); - } - tmp.putAll(additional); - return tmp; - } - -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java deleted file mode 100644 index 192630a5656..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2015, 2025, 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 jdk.jpackage.internal; - -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.Map; -import java.util.Objects; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; - - -class AppImageBundler extends AbstractBundler { - - @Override - public final String getName() { - return I18N.getString("app.bundler.name"); - } - - @Override - public final String getID() { - return "app"; - } - - @Override - public final String getBundleType() { - return "IMAGE"; - } - - @Override - public final boolean validate(Map params) - throws ConfigException { - try { - Objects.requireNonNull(params); - - if (!params.containsKey(PREDEFINED_APP_IMAGE.getID()) - && !StandardBundlerParam.isRuntimeInstaller(params)) { - LAUNCHER_DATA.fetchFrom(params); - } - - if (paramsValidator != null) { - paramsValidator.validate(params); - } - } catch (RuntimeException re) { - if (re.getCause() instanceof ConfigException) { - throw (ConfigException) re.getCause(); - } else { - throw new ConfigException(re); - } - } - - return true; - } - - @Override - public final Path execute(Map params, - Path outputParentDir) throws PackagerException { - - final var predefinedAppImage = PREDEFINED_APP_IMAGE.fetchFrom(params); - - try { - if (predefinedAppImage == null) { - Path rootDirectory = createRoot(params, outputParentDir); - appImageSupplier.prepareApplicationFiles(params, rootDirectory); - return rootDirectory; - } else { - appImageSupplier.prepareApplicationFiles(params, predefinedAppImage); - return predefinedAppImage; - } - } catch (PackagerException pe) { - throw pe; - } catch (RuntimeException|IOException ex) { - Log.verbose(ex); - throw new PackagerException(ex); - } - } - - @Override - public final boolean supported(boolean runtimeInstaller) { - return true; - } - - @Override - public final boolean isDefault() { - return false; - } - - @FunctionalInterface - static interface AppImageSupplier { - - void prepareApplicationFiles(Map params, - Path root) throws PackagerException, IOException; - } - - final AppImageBundler setAppImageSupplier(AppImageSupplier v) { - appImageSupplier = v; - return this; - } - - final AppImageBundler setParamsValidator(ParamsValidator v) { - paramsValidator = v; - return this; - } - - @FunctionalInterface - interface ParamsValidator { - void validate(Map params) throws ConfigException; - } - - private Path createRoot(Map params, - Path outputDirectory) throws PackagerException, IOException { - - IOUtils.writableOutputDir(outputDirectory); - - String imageName = APP_NAME.fetchFrom(params); - if (OperatingSystem.isMacOS()) { - imageName = imageName + ".app"; - } - - Log.verbose(MessageFormat.format( - I18N.getString("message.creating-app-bundle"), - imageName, outputDirectory.toAbsolutePath())); - - // Create directory structure - Path rootDirectory = outputDirectory.resolve(imageName); - if (Files.exists(rootDirectory)) { - throw new PackagerException("error.root-exists", - rootDirectory.toAbsolutePath().toString()); - } - - Files.createDirectories(rootDirectory); - - return rootDirectory; - } - - private ParamsValidator paramsValidator; - private AppImageSupplier appImageSupplier; -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 8b8a22edc56..b6b4322302e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -25,148 +25,149 @@ package jdk.jpackage.internal; import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toMap; -import static java.util.stream.Collectors.toSet; +import static java.util.stream.Collectors.toUnmodifiableMap; +import static java.util.stream.Collectors.toUnmodifiableSet; +import static jdk.jpackage.internal.cli.StandardAppImageFileOption.APP_VERSION; +import static jdk.jpackage.internal.cli.StandardAppImageFileOption.LAUNCHER_AS_SERVICE; +import static jdk.jpackage.internal.cli.StandardAppImageFileOption.DESCRIPTION; +import static jdk.jpackage.internal.cli.StandardAppImageFileOption.LAUNCHER_NAME; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import java.io.IOException; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.stream.Stream; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.cli.OptionValue; +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.cli.StandardAppImageFileOption.AppImageFileOptionScope; +import jdk.jpackage.internal.cli.StandardAppImageFileOption.InvalidOptionValueException; +import jdk.jpackage.internal.cli.StandardAppImageFileOption.MissingMandatoryOptionException; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.ExternalApplication; +import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.util.XmlUtils; +import jdk.jpackage.internal.util.function.ExceptionBox; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.SAXException; -final class AppImageFile implements ExternalApplication { +final class AppImageFile { AppImageFile(Application app) { - this(new ApplicationData(app)); - } - - private AppImageFile(ApplicationData app) { - - appVersion = app.version(); - launcherName = app.mainLauncherName(); - mainClass = app.mainLauncherMainClassName(); - extra = app.extra; - creatorVersion = getVersion(); - creatorPlatform = getPlatform(); - addLauncherInfos = app.additionalLaunchers; - } - - @Override - public List getAddLaunchers() { - return addLauncherInfos; - } - - @Override - public String getAppVersion() { - return appVersion; - } - - @Override - public String getAppName() { - return launcherName; - } - - @Override - public String getLauncherName() { - return launcherName; - } - - @Override - public String getMainClass() { - return mainClass; - } - - @Override - public Map getExtra() { - return extra; + appVersion = Objects.requireNonNull(app.version()); + extra = Objects.requireNonNull(app.extraAppImageFileData()); + launcherInfos = app.launchers().stream().map(LauncherInfo::new).toList(); } /** - * Saves file with application image info in application image using values - * from this instance. + * Writes the values captured in this instance into the application image info + * file in the given application layout. + *

    + * It is an equivalent to calling + * {@link #save(ApplicationLayout, OperatingSystem)} method with + * {@code OperatingSystem.current()} for the second parameter. + * + * @param appLayout the application layout + * @throws IOException if an I/O error occurs when writing */ void save(ApplicationLayout appLayout) throws IOException { + save(appLayout, OperatingSystem.current()); + } + + /** + * Writes the values captured in this instance into the application image info + * file in the given application layout. + * + * @param appLayout the application layout + * @param os the target OS + * @throws IOException if an I/O error occurs when writing + */ + void save(ApplicationLayout appLayout, OperatingSystem os) throws IOException { XmlUtils.createXml(getPathInAppImage(appLayout), xml -> { xml.writeStartElement("jpackage-state"); - xml.writeAttribute("version", creatorVersion); - xml.writeAttribute("platform", creatorPlatform); + xml.writeAttribute("version", getVersion()); + xml.writeAttribute("platform", getPlatform(os)); xml.writeStartElement("app-version"); xml.writeCharacters(appVersion); xml.writeEndElement(); - xml.writeStartElement("main-launcher"); - xml.writeCharacters(launcherName); - xml.writeEndElement(); - - xml.writeStartElement("main-class"); - xml.writeCharacters(mainClass); - xml.writeEndElement(); - for (var extraKey : extra.keySet().stream().sorted().toList()) { xml.writeStartElement(extraKey); xml.writeCharacters(extra.get(extraKey)); xml.writeEndElement(); } - for (var li : addLauncherInfos) { - xml.writeStartElement("add-launcher"); - xml.writeAttribute("name", li.name()); - xml.writeAttribute("service", Boolean.toString(li.service())); - for (var extraKey : li.extra().keySet().stream().sorted().toList()) { - xml.writeStartElement(extraKey); - xml.writeCharacters(li.extra().get(extraKey)); - xml.writeEndElement(); - } - xml.writeEndElement(); + launcherInfos.getFirst().save(xml, "main-launcher"); + + for (var li : launcherInfos.subList(1, launcherInfos.size())) { + li.save(xml, "add-launcher"); } }); } /** - * Returns path to application image info file. - * @param appLayout - application layout + * Returns the path to the application image info file in the given application layout. + * + * @param appLayout the application layout */ static Path getPathInAppImage(ApplicationLayout appLayout) { return appLayout.appDirectory().resolve(FILENAME); } /** - * Loads application image info from application image. - * @param appImageDir - path at which to resolve the given application layout - * @param appLayout - application layout + * Loads application image info from the specified application layout. + *

    + * It is an equivalent to calling + * {@link #load(ApplicationLayout, OperatingSystem)} method with + * {@code OperatingSystem.current()} for the second parameter. + * + * @param appLayout the application layout */ - static AppImageFile load(Path appImageDir, ApplicationLayout appLayout) throws ConfigException, IOException { - var srcFilePath = getPathInAppImage(appLayout.resolveAt(appImageDir)); + static ExternalApplication load(ApplicationLayout appLayout) { + return load(appLayout, OperatingSystem.current()); + } + + /** + * Loads application image info from the specified application layout and OS. + * + * @param appLayout the application layout + * @param os the OS defining extra properties of the application and + * additional launchers + */ + static ExternalApplication load(ApplicationLayout appLayout, OperatingSystem os) { + Objects.requireNonNull(appLayout); + Objects.requireNonNull(os); + + final var appImageDir = appLayout.rootDirectory(); + final var appImageFilePath = getPathInAppImage(appLayout); + final var relativeAppImageFilePath = appImageDir.relativize(appImageFilePath); + try { - final Document doc = XmlUtils.initDocumentBuilder().parse(Files.newInputStream(srcFilePath)); + final Document doc = XmlUtils.initDocumentBuilder().parse(Files.newInputStream(appImageFilePath)); final XPath xPath = XPathFactory.newInstance().newXPath(); final var isPlatformValid = XmlUtils.queryNodes(doc, xPath, "/jpackage-state/@platform").findFirst().map( - Node::getNodeValue).map(getPlatform()::equals).orElse(false); + Node::getNodeValue).map(getPlatform(os)::equals).orElse(false); if (!isPlatformValid) { throw new InvalidAppImageFileException(); } @@ -177,102 +178,73 @@ final class AppImageFile implements ExternalApplication { throw new InvalidAppImageFileException(); } - final AppImageProperties props; + final var appOptions = AppImageFileOptionScope.APP.parse(appImageFilePath, AppImageProperties.main(doc, xPath), os); + + final var mainLauncherOptions = LauncherElement.MAIN.readAll(doc, xPath).stream().reduce((_, second) -> { + return second; + }).map(launcherProps -> { + return AppImageFileOptionScope.LAUNCHER.parse(appImageFilePath, launcherProps, os); + }).orElseThrow(InvalidAppImageFileException::new); + + final var addLauncherOptions = LauncherElement.ADDITIONAL.readAll(doc, xPath).stream().map(launcherProps -> { + return AppImageFileOptionScope.LAUNCHER.parse(appImageFilePath, launcherProps, os); + }).toList(); + try { - props = AppImageProperties.main(doc, xPath); - } catch (IllegalArgumentException ex) { + return ExternalApplication.create(Options.concat(appOptions, mainLauncherOptions), addLauncherOptions, os); + } catch (NoSuchElementException ex) { throw new InvalidAppImageFileException(ex); } - final var additionalLaunchers = AppImageProperties.launchers(doc, xPath).stream().map(launcherProps -> { - try { - return new LauncherInfo(launcherProps.get("name"), - launcherProps.find("service").map(Boolean::parseBoolean).orElse(false), launcherProps.getExtra()); - } catch (IllegalArgumentException ex) { - throw new InvalidAppImageFileException(ex); - } - }).toList(); - - return new AppImageFile(new ApplicationData(props.get("app-version"), props.get("main-launcher"), - props.get("main-class"), props.getExtra(), additionalLaunchers)); - } catch (XPathExpressionException ex) { // This should never happen as XPath expressions should be correct - throw new RuntimeException(ex); + throw ExceptionBox.rethrowUnchecked(ex); } catch (SAXException ex) { - // Exception reading input XML (probably malformed XML) - throw new IOException(ex); + // Malformed input XML + throw new JPackageException(I18N.format("error.malformed-app-image-file", relativeAppImageFilePath, appImageDir), ex); } catch (NoSuchFileException ex) { - throw I18N.buildConfigException("error.foreign-app-image", appImageDir).create(); - } catch (InvalidAppImageFileException ex) { + // Don't save the original exception as its error message is redundant. + throw new JPackageException(I18N.format("error.missing-app-image-file", relativeAppImageFilePath, appImageDir)); + } catch (InvalidAppImageFileException|InvalidOptionValueException|MissingMandatoryOptionException ex) { // Invalid input XML - throw I18N.buildConfigException("error.invalid-app-image", appImageDir, srcFilePath).create(); + throw new JPackageException(I18N.format("error.invalid-app-image-file", relativeAppImageFilePath, appImageDir), ex); + } catch (IOException ex) { + throw new JPackageException(I18N.format("error.reading-app-image-file", relativeAppImageFilePath, appImageDir), ex); } } - static boolean getBooleanExtraFieldValue(String fieldId, ExternalApplication appImageFile) { - Objects.requireNonNull(fieldId); - Objects.requireNonNull(appImageFile); - return Optional.ofNullable(appImageFile.getExtra().get(fieldId)).map(Boolean::parseBoolean).orElse(false); - } - static String getVersion() { return System.getProperty("java.version"); } - static String getPlatform() { - return PLATFORM_LABELS.get(OperatingSystem.current()); + static String getPlatform(OperatingSystem os) { + return Objects.requireNonNull(PLATFORM_LABELS.get(Objects.requireNonNull(os))); } + private static final class AppImageProperties { - private AppImageProperties(Map data, Set stdKeys) { - this.data = data; - this.stdKeys = stdKeys; + + static Map main(Document xml, XPath xPath) throws XPathExpressionException { + return queryProperties(xml.getDocumentElement(), xPath, MAIN_PROPERTIES_XPATH_QUERY); } - static AppImageProperties main(Document xml, XPath xPath) throws XPathExpressionException { - final var data = queryProperties(xml.getDocumentElement(), xPath, MAIN_PROPERTIES_XPATH_QUERY); - return new AppImageProperties(data, MAIN_ELEMENT_NAMES); - } + static Map launcher(Element launcherNode, XPath xPath) throws XPathExpressionException { + final var attrData = XmlUtils.toStream(launcherNode.getAttributes()) + .collect(toUnmodifiableMap(Node::getNodeName, Node::getNodeValue)); - static AppImageProperties launcher(Element addLauncherNode, XPath xPath) throws XPathExpressionException { - final var attrData = XmlUtils.toStream(addLauncherNode.getAttributes()) - .collect(toMap(Node::getNodeName, Node::getNodeValue)); - - final var extraData = queryProperties(addLauncherNode, xPath, LAUNCHER_PROPERTIES_XPATH_QUERY); + final var extraData = queryProperties(launcherNode, xPath, LAUNCHER_PROPERTIES_XPATH_QUERY); final Map data = new HashMap<>(attrData); data.putAll(extraData); - return new AppImageProperties(data, LAUNCHER_ATTR_NAMES); - } - - static List launchers(Document xml, XPath xPath) throws XPathExpressionException { - return XmlUtils.queryNodes(xml, xPath, "/jpackage-state/add-launcher") - .map(Element.class::cast).map(toFunction(e -> { - return launcher(e, xPath); - })).toList(); - } - - String get(String name) { - return find(name).orElseThrow(InvalidAppImageFileException::new); - } - - Optional find(String name) { - return Optional.ofNullable(data.get(name)); - } - - Map getExtra() { - Map extra = new HashMap<>(data); - stdKeys.forEach(extra::remove); - return extra; + return data; } private static Map queryProperties(Element e, XPath xPath, String xpathExpr) throws XPathExpressionException { return XmlUtils.queryNodes(e, xPath, xpathExpr) .map(Element.class::cast) - .collect(toMap(Node::getNodeName, selectedElement -> { + .collect(toUnmodifiableMap(Node::getNodeName, selectedElement -> { return selectedElement.getTextContent(); }, (a, b) -> b)); } @@ -285,13 +257,14 @@ final class AppImageFile implements ExternalApplication { return String.format("*[(%s) and not(*)]", otherElementNames); } - private final Map data; - private final Set stdKeys; - - private static final Set LAUNCHER_ATTR_NAMES = Set.of("name", "service"); + private static final Set LAUNCHER_ATTR_NAMES = Stream.of( + LAUNCHER_NAME + ).map(OptionValue::getName).collect(toUnmodifiableSet()); private static final String LAUNCHER_PROPERTIES_XPATH_QUERY = xpathQueryForExtraProperties(LAUNCHER_ATTR_NAMES); - private static final Set MAIN_ELEMENT_NAMES = Set.of("app-version", "main-launcher", "main-class"); + private static final Set MAIN_ELEMENT_NAMES = Stream.of( + APP_VERSION + ).map(OptionValue::getName).collect(toUnmodifiableSet()); private static final String MAIN_PROPERTIES_XPATH_QUERY; static { @@ -301,40 +274,65 @@ final class AppImageFile implements ExternalApplication { MAIN_PROPERTIES_XPATH_QUERY = String.format("%s|/jpackage-state/%s", nonEmptyMainElements, xpathQueryForExtraProperties(Stream.concat(MAIN_ELEMENT_NAMES.stream(), - Stream.of("add-launcher")).collect(toSet()))); + Stream.of("main-launcher", "add-launcher")).collect(toUnmodifiableSet()))); } } - private record ApplicationData(String version, String mainLauncherName, String mainLauncherMainClassName, - Map extra, List additionalLaunchers) { - ApplicationData { - Objects.requireNonNull(version); - Objects.requireNonNull(mainLauncherName); - Objects.requireNonNull(mainLauncherMainClassName); - Objects.requireNonNull(extra); - Objects.requireNonNull(additionalLaunchers); + private enum LauncherElement { + MAIN("main-launcher"), + ADDITIONAL("add-launcher"); - for (final var property : List.of(version, mainLauncherName, mainLauncherMainClassName)) { - if (property.isBlank()) { - throw new IllegalArgumentException(); - } + LauncherElement(String elementName) { + this.elementName = Objects.requireNonNull(elementName); + } + + List> readAll(Document xml, XPath xPath) throws XPathExpressionException { + return XmlUtils.queryNodes(xml, xPath, "/jpackage-state/" + elementName + "[@name]") + .map(Element.class::cast).map(toFunction(e -> { + return AppImageProperties.launcher(e, xPath); + })).toList(); + } + + private final String elementName; + } + + private record LauncherInfo(String name, Map properties) { + LauncherInfo { + Objects.requireNonNull(name); + Objects.requireNonNull(properties); + } + + LauncherInfo(Launcher launcher) { + this(launcher.name(), properties(launcher)); + } + + void save(XMLStreamWriter xml, String elementName) throws IOException, XMLStreamException { + xml.writeStartElement(elementName); + xml.writeAttribute("name", name()); + for (var key : properties().keySet().stream().sorted().toList()) { + xml.writeStartElement(key); + xml.writeCharacters(properties().get(key)); + xml.writeEndElement(); } + xml.writeEndElement(); } - ApplicationData(Application app) { - this(app, app.mainLauncher().orElseThrow()); - } + private static Map properties(Launcher launcher) { + List> standardProps = new ArrayList<>(); + if (launcher.isService()) { + standardProps.add(Map.entry(LAUNCHER_AS_SERVICE.getName(), Boolean.TRUE.toString())); + } + standardProps.add(Map.entry(DESCRIPTION.getName(), launcher.description())); - private ApplicationData(Application app, Launcher mainLauncher) { - this(app.version(), mainLauncher.name(), mainLauncher.startupInfo().orElseThrow().qualifiedClassName(), - app.extraAppImageFileData(), app.additionalLaunchers().stream().map(launcher -> { - return new LauncherInfo(launcher.name(), launcher.isService(), - launcher.extraAppImageFileData()); - }).toList()); + return Stream.concat( + standardProps.stream(), + launcher.extraAppImageFileData().entrySet().stream() + ).collect(toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue)); } } + private static class InvalidAppImageFileException extends RuntimeException { InvalidAppImageFileException() { @@ -347,13 +345,10 @@ final class AppImageFile implements ExternalApplication { private static final long serialVersionUID = 1L; } + private final String appVersion; - private final String launcherName; - private final String mainClass; private final Map extra; - private final List addLauncherInfos; - private final String creatorVersion; - private final String creatorPlatform; + private final List launcherInfos; private static final String FILENAME = ".jpackage.xml"; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 76a5fc1a50c..6896668ffdc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -38,9 +38,7 @@ import java.util.function.Predicate; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.ExternalApplication; -import jdk.jpackage.internal.model.ExternalApplication.LauncherInfo; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.LauncherIcon; import jdk.jpackage.internal.model.LauncherStartupInfo; @@ -49,28 +47,17 @@ import jdk.jpackage.internal.model.RuntimeBuilder; final class ApplicationBuilder { - Application create() throws ConfigException { + Application create() { Objects.requireNonNull(appImageLayout); final var launchersAsList = Optional.ofNullable(launchers).map( ApplicationLaunchers::asList).orElseGet(List::of); - final var launcherCount = launchersAsList.size(); - - if (launcherCount != launchersAsList.stream().map(Launcher::name).distinct().count()) { - throw buildConfigException("ERR_NoUniqueName").create(); - } - - final String effectiveName; - if (name != null) { - effectiveName = name; - } else if (!launchersAsList.isEmpty()) { - effectiveName = launchers.mainLauncher().name(); - } else { - throw buildConfigException("error.no.name").advice("error.no.name.advice").create(); - } - - Objects.requireNonNull(launchersAsList); + final String effectiveName = Optional.ofNullable(name).or(() -> { + return Optional.ofNullable(launchers).map(ApplicationLaunchers::mainLauncher).map(Launcher::name); + }).orElseThrow(() -> { + return buildConfigException("error.no.name").advice("error.no.name.advice").create(); + }); return new Application.Stub( effectiveName, @@ -80,7 +67,10 @@ final class ApplicationBuilder { Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), Optional.ofNullable(srcDir), Optional.ofNullable(contentDirs).orElseGet(List::of), - appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList, Map.of()); + appImageLayout, + Optional.ofNullable(runtimeBuilder), + launchersAsList, + Map.of()); } ApplicationBuilder runtimeBuilder(RuntimeBuilder v) { @@ -88,25 +78,8 @@ final class ApplicationBuilder { return this; } - ApplicationBuilder initFromExternalApplication(ExternalApplication app, - Function mapper) { - - externalApp = Objects.requireNonNull(app); - - if (version == null) { - version = app.getAppVersion(); - } - if (name == null) { - name = app.getAppName(); - } - runtimeBuilder = null; - - var mainLauncherInfo = new LauncherInfo(app.getLauncherName(), false, Map.of()); - - launchers = new ApplicationLaunchers( - mapper.apply(mainLauncherInfo), - app.getAddLaunchers().stream().map(mapper).toList()); - + ApplicationBuilder externalApplication(ExternalApplication v) { + externalApp = v; return this; } @@ -123,15 +96,6 @@ final class ApplicationBuilder { return Optional.ofNullable(externalApp); } - Optional mainLauncherClassName() { - return launchers() - .map(ApplicationLaunchers::mainLauncher) - .flatMap(Launcher::startupInfo) - .map(LauncherStartupInfo::qualifiedClassName).or(() -> { - return externalApplication().map(ExternalApplication::getMainClass); - }); - } - ApplicationBuilder appImageLayout(AppImageLayout v) { appImageLayout = v; return this; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java deleted file mode 100644 index 0ea72ae160c..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayoutUtils.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.jpackage.internal; - -import java.nio.file.Path; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.model.ApplicationLayout; - - -final class ApplicationLayoutUtils { - - public static final ApplicationLayout PLATFORM_APPLICATION_LAYOUT; - - private static final ApplicationLayout WIN_APPLICATION_LAYOUT = ApplicationLayout.build() - .setAll("") - .appDirectory("app") - .runtimeDirectory("runtime") - .appModsDirectory(Path.of("app", "mods")) - .create(); - - private static final ApplicationLayout MAC_APPLICATION_LAYOUT = ApplicationLayout.build() - .launchersDirectory("Contents/MacOS") - .appDirectory("Contents/app") - .runtimeDirectory("Contents/runtime/Contents/Home") - .desktopIntegrationDirectory("Contents/Resources") - .appModsDirectory("Contents/app/mods") - .contentDirectory("Contents") - .create(); - - private static final ApplicationLayout LINUX_APPLICATION_LAYOUT = ApplicationLayout.build() - .launchersDirectory("bin") - .appDirectory("lib/app") - .runtimeDirectory("lib/runtime") - .desktopIntegrationDirectory("lib") - .appModsDirectory("lib/app/mods") - .contentDirectory("lib") - .create(); - - static { - switch (OperatingSystem.current()) { - case WINDOWS -> PLATFORM_APPLICATION_LAYOUT = WIN_APPLICATION_LAYOUT; - case MACOS -> PLATFORM_APPLICATION_LAYOUT = MAC_APPLICATION_LAYOUT; - case LINUX -> PLATFORM_APPLICATION_LAYOUT = LINUX_APPLICATION_LAYOUT; - default -> { - throw new UnsupportedOperationException(); - } - } - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java deleted file mode 100644 index f0323bbd841..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ /dev/null @@ -1,867 +0,0 @@ -/* - * Copyright (c) 2018, 2025, 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 jdk.jpackage.internal; - -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; -import java.io.IOException; -import java.io.Reader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Properties; -import java.util.ResourceBundle; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Arguments - * - * This class encapsulates and processes the command line arguments, - * in effect, implementing all the work of jpackage tool. - * - * The primary entry point, processArguments(): - * Processes and validates command line arguments, constructing DeployParams. - * Validates the DeployParams, and generate the BundleParams. - * Generates List of Bundlers from BundleParams valid for this platform. - * Executes each Bundler in the list. - */ -public class Arguments { - private static final ResourceBundle I18N = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.MainResources"); - - private static final String FA_EXTENSIONS = "extension"; - private static final String FA_CONTENT_TYPE = "mime-type"; - private static final String FA_DESCRIPTION = "description"; - private static final String FA_ICON = "icon"; - - // Mac specific file association keys - // String - public static final String MAC_CFBUNDLETYPEROLE = "mac.CFBundleTypeRole"; - public static final String MAC_LSHANDLERRANK = "mac.LSHandlerRank"; - public static final String MAC_NSSTORETYPEKEY = "mac.NSPersistentStoreTypeKey"; - public static final String MAC_NSDOCUMENTCLASS = "mac.NSDocumentClass"; - // Boolean - public static final String MAC_LSTYPEISPACKAGE = "mac.LSTypeIsPackage"; - public static final String MAC_LSDOCINPLACE = "mac.LSSupportsOpeningDocumentsInPlace"; - public static final String MAC_UIDOCBROWSER = "mac.UISupportsDocumentBrowser"; - // Array of strings - public static final String MAC_NSEXPORTABLETYPES = "mac.NSExportableTypes"; - public static final String MAC_UTTYPECONFORMSTO = "mac.UTTypeConformsTo"; - - // regexp for parsing args (for example, for additional launchers) - private static Pattern pattern = Pattern.compile( - "(?:(?:([\"'])(?:\\\\\\1|.)*?(?:\\1|$))|(?:\\\\[\"'\\s]|[^\\s]))++"); - - private DeployParams deployParams = null; - - private int pos = 0; - private List argList = null; - - private List allOptions = null; - - private boolean hasMainJar = false; - private boolean hasMainClass = false; - private boolean hasMainModule = false; - public boolean userProvidedBuildRoot = false; - - private String buildRoot = null; - private String mainJarPath = null; - - private boolean runtimeInstaller = false; - - private List addLaunchers = null; - - private static final Map argIds = new HashMap<>(); - private static final Map argShortIds = new HashMap<>(); - - static { - // init maps for parsing arguments - (EnumSet.allOf(CLIOptions.class)).forEach(option -> { - argIds.put(option.getIdWithPrefix(), option); - if (option.getShortIdWithPrefix() != null) { - argShortIds.put(option.getShortIdWithPrefix(), option); - } - }); - } - - private static final InheritableThreadLocal instance = - new InheritableThreadLocal(); - - public Arguments(String[] args) { - instance.set(this); - - argList = new ArrayList(args.length); - for (String arg : args) { - argList.add(arg); - } - - pos = 0; - - deployParams = new DeployParams(); - - allOptions = new ArrayList<>(); - - addLaunchers = new ArrayList<>(); - } - - // CLIOptions is public for DeployParamsTest - public enum CLIOptions { - PACKAGE_TYPE("type", "t", OptionCategories.PROPERTY, () -> { - var type = popArg(); - context().deployParams.setTargetFormat(type); - setOptionValue("type", type); - }), - - INPUT ("input", "i", OptionCategories.PROPERTY, () -> { - setOptionValue("input", popArg()); - }), - - OUTPUT ("dest", "d", OptionCategories.PROPERTY, () -> { - var path = Path.of(popArg()); - setOptionValue("dest", path); - }), - - DESCRIPTION ("description", OptionCategories.PROPERTY), - - VENDOR ("vendor", OptionCategories.PROPERTY), - - APPCLASS ("main-class", OptionCategories.PROPERTY, () -> { - context().hasMainClass = true; - setOptionValue("main-class", popArg()); - }), - - NAME ("name", "n", OptionCategories.PROPERTY), - - VERBOSE ("verbose", OptionCategories.PROPERTY, () -> { - setOptionValue("verbose", true); - Log.setVerbose(); - }), - - RESOURCE_DIR("resource-dir", - OptionCategories.PROPERTY, () -> { - String resourceDir = popArg(); - setOptionValue("resource-dir", resourceDir); - }), - - DMG_CONTENT ("mac-dmg-content", OptionCategories.PROPERTY, () -> { - List content = getArgumentList(popArg()); - content.forEach(a -> setOptionValue("mac-dmg-content", a)); - }), - - ARGUMENTS ("arguments", OptionCategories.PROPERTY, () -> { - List arguments = getArgumentList(popArg()); - setOptionValue("arguments", arguments); - }), - - JLINK_OPTIONS ("jlink-options", OptionCategories.PROPERTY, () -> { - List options = getArgumentList(popArg()); - setOptionValue("jlink-options", options); - }), - - ICON ("icon", OptionCategories.PROPERTY), - - COPYRIGHT ("copyright", OptionCategories.PROPERTY), - - LICENSE_FILE ("license-file", OptionCategories.PROPERTY), - - VERSION ("app-version", OptionCategories.PROPERTY), - - RELEASE ("linux-app-release", OptionCategories.PROPERTY), - - ABOUT_URL ("about-url", OptionCategories.PROPERTY), - - JAVA_OPTIONS ("java-options", OptionCategories.PROPERTY, () -> { - List args = getArgumentList(popArg()); - args.forEach(a -> setOptionValue("java-options", a)); - }), - - APP_CONTENT ("app-content", OptionCategories.PROPERTY, () -> { - getArgumentList(popArg()).forEach( - a -> setOptionValue("app-content", a)); - }), - - FILE_ASSOCIATIONS ("file-associations", - OptionCategories.PROPERTY, () -> { - Map args = new HashMap<>(); - - // load .properties file - Map initialMap = getPropertiesFromFile(popArg()); - - putUnlessNull(args, StandardBundlerParam.FA_EXTENSIONS.getID(), - initialMap.get(FA_EXTENSIONS)); - - putUnlessNull(args, StandardBundlerParam.FA_CONTENT_TYPE.getID(), - initialMap.get(FA_CONTENT_TYPE)); - - putUnlessNull(args, StandardBundlerParam.FA_DESCRIPTION.getID(), - initialMap.get(FA_DESCRIPTION)); - - putUnlessNull(args, StandardBundlerParam.FA_ICON.getID(), - initialMap.get(FA_ICON)); - - // Mac extended file association arguments - putUnlessNull(args, MAC_CFBUNDLETYPEROLE, - initialMap.get(MAC_CFBUNDLETYPEROLE)); - - putUnlessNull(args, MAC_LSHANDLERRANK, - initialMap.get(MAC_LSHANDLERRANK)); - - putUnlessNull(args, MAC_NSSTORETYPEKEY, - initialMap.get(MAC_NSSTORETYPEKEY)); - - putUnlessNull(args, MAC_NSDOCUMENTCLASS, - initialMap.get(MAC_NSDOCUMENTCLASS)); - - putUnlessNull(args, MAC_LSTYPEISPACKAGE, - initialMap.get(MAC_LSTYPEISPACKAGE)); - - putUnlessNull(args, MAC_LSDOCINPLACE, - initialMap.get(MAC_LSDOCINPLACE)); - - putUnlessNull(args, MAC_UIDOCBROWSER, - initialMap.get(MAC_UIDOCBROWSER)); - - putUnlessNull(args, MAC_NSEXPORTABLETYPES, - initialMap.get(MAC_NSEXPORTABLETYPES)); - - putUnlessNull(args, MAC_UTTYPECONFORMSTO, - initialMap.get(MAC_UTTYPECONFORMSTO)); - - ArrayList> associationList = - new ArrayList>(); - - associationList.add(args); - - // check that we really add _another_ value to the list - setOptionValue("file-associations", associationList); - - }), - - ADD_LAUNCHER ("add-launcher", - OptionCategories.PROPERTY, () -> { - String spec = popArg(); - String name = null; - String filename = spec; - if (spec.contains("=")) { - String[] values = spec.split("=", 2); - name = values[0]; - filename = values[1]; - } - context().addLaunchers.add( - new AddLauncherArguments(name, filename)); - }), - - TEMP_ROOT ("temp", OptionCategories.PROPERTY, () -> { - context().buildRoot = popArg(); - context().userProvidedBuildRoot = true; - setOptionValue("temp", context().buildRoot); - }), - - INSTALL_DIR ("install-dir", OptionCategories.PROPERTY), - - PREDEFINED_APP_IMAGE ("app-image", OptionCategories.PROPERTY), - - PREDEFINED_RUNTIME_IMAGE ("runtime-image", OptionCategories.PROPERTY), - - MAIN_JAR ("main-jar", OptionCategories.PROPERTY, () -> { - context().mainJarPath = popArg(); - context().hasMainJar = true; - setOptionValue("main-jar", context().mainJarPath); - }), - - MODULE ("module", "m", OptionCategories.MODULAR, () -> { - context().hasMainModule = true; - setOptionValue("module", popArg()); - }), - - ADD_MODULES ("add-modules", OptionCategories.MODULAR), - - MODULE_PATH ("module-path", "p", OptionCategories.MODULAR), - - LAUNCHER_AS_SERVICE ("launcher-as-service", OptionCategories.PROPERTY, () -> { - setOptionValue("launcher-as-service", true); - }), - - MAC_SIGN ("mac-sign", "s", OptionCategories.PLATFORM_MAC, () -> { - setOptionValue("mac-sign", true); - }), - - MAC_APP_STORE ("mac-app-store", OptionCategories.PLATFORM_MAC, () -> { - setOptionValue("mac-app-store", true); - }), - - MAC_CATEGORY ("mac-app-category", OptionCategories.PLATFORM_MAC), - - MAC_BUNDLE_NAME ("mac-package-name", OptionCategories.PLATFORM_MAC), - - MAC_BUNDLE_IDENTIFIER("mac-package-identifier", - OptionCategories.PLATFORM_MAC), - - MAC_BUNDLE_SIGNING_PREFIX ("mac-package-signing-prefix", - OptionCategories.PLATFORM_MAC), - - MAC_SIGNING_KEY_NAME ("mac-signing-key-user-name", - OptionCategories.PLATFORM_MAC), - - MAC_APP_IMAGE_SIGN_IDENTITY ("mac-app-image-sign-identity", - OptionCategories.PLATFORM_MAC), - - MAC_INSTALLER_SIGN_IDENTITY ("mac-installer-sign-identity", - OptionCategories.PLATFORM_MAC), - - MAC_SIGNING_KEYCHAIN ("mac-signing-keychain", - OptionCategories.PLATFORM_MAC), - - MAC_ENTITLEMENTS ("mac-entitlements", OptionCategories.PLATFORM_MAC), - - WIN_HELP_URL ("win-help-url", OptionCategories.PLATFORM_WIN), - - WIN_UPDATE_URL ("win-update-url", OptionCategories.PLATFORM_WIN), - - WIN_MENU_HINT ("win-menu", OptionCategories.PLATFORM_WIN, - createArgumentWithOptionalValueAction("win-menu")), - - WIN_MENU_GROUP ("win-menu-group", OptionCategories.PLATFORM_WIN), - - WIN_SHORTCUT_HINT ("win-shortcut", OptionCategories.PLATFORM_WIN, - createArgumentWithOptionalValueAction("win-shortcut")), - - WIN_SHORTCUT_PROMPT ("win-shortcut-prompt", - OptionCategories.PLATFORM_WIN, () -> { - setOptionValue("win-shortcut-prompt", true); - }), - - WIN_PER_USER_INSTALLATION ("win-per-user-install", - OptionCategories.PLATFORM_WIN, () -> { - setOptionValue("win-per-user-install", false); - }), - - WIN_DIR_CHOOSER ("win-dir-chooser", - OptionCategories.PLATFORM_WIN, () -> { - setOptionValue("win-dir-chooser", true); - }), - - WIN_UPGRADE_UUID ("win-upgrade-uuid", - OptionCategories.PLATFORM_WIN), - - WIN_CONSOLE_HINT ("win-console", OptionCategories.PLATFORM_WIN, () -> { - setOptionValue("win-console", true); - }), - - LINUX_BUNDLE_NAME ("linux-package-name", - OptionCategories.PLATFORM_LINUX), - - LINUX_DEB_MAINTAINER ("linux-deb-maintainer", - OptionCategories.PLATFORM_LINUX), - - LINUX_CATEGORY ("linux-app-category", - OptionCategories.PLATFORM_LINUX), - - LINUX_RPM_LICENSE_TYPE ("linux-rpm-license-type", - OptionCategories.PLATFORM_LINUX), - - LINUX_PACKAGE_DEPENDENCIES ("linux-package-deps", - OptionCategories.PLATFORM_LINUX), - - LINUX_SHORTCUT_HINT ("linux-shortcut", OptionCategories.PLATFORM_LINUX, - createArgumentWithOptionalValueAction("linux-shortcut")), - - LINUX_MENU_GROUP ("linux-menu-group", OptionCategories.PLATFORM_LINUX); - - private final String id; - private final String shortId; - private final OptionCategories category; - private final Runnable action; - private static Arguments argContext; - - private CLIOptions(String id, OptionCategories category) { - this(id, null, category, null); - } - - private CLIOptions(String id, String shortId, - OptionCategories category) { - this(id, shortId, category, null); - } - - private CLIOptions(String id, - OptionCategories category, Runnable action) { - this(id, null, category, action); - } - - private CLIOptions(String id, String shortId, - OptionCategories category, Runnable action) { - this.id = id; - this.shortId = shortId; - this.action = action; - this.category = category; - } - - public static Arguments context() { - return instance.get(); - } - - public String getId() { - return this.id; - } - - String getIdWithPrefix() { - return "--" + this.id; - } - - String getShortIdWithPrefix() { - return this.shortId == null ? null : "-" + this.shortId; - } - - void execute() { - if (action != null) { - action.run(); - } else { - defaultAction(); - } - } - - private void defaultAction() { - context().deployParams.addBundleArgument(id, popArg()); - } - - private static void setOptionValue(String option, Object value) { - context().deployParams.addBundleArgument(option, value); - } - - private static String popArg() { - nextArg(); - return (context().pos >= context().argList.size()) ? - "" : context().argList.get(context().pos); - } - - private static String getArg() { - return (context().pos >= context().argList.size()) ? - "" : context().argList.get(context().pos); - } - - private static void nextArg() { - context().pos++; - } - - private static void prevArg() { - Objects.checkIndex(context().pos, context().argList.size()); - context().pos--; - } - - private static boolean hasNextArg() { - return context().pos < context().argList.size(); - } - - private static Runnable createArgumentWithOptionalValueAction(String option) { - Objects.requireNonNull(option); - return () -> { - nextArg(); - if (hasNextArg()) { - var value = getArg(); - if (value.startsWith("-")) { - prevArg(); - setOptionValue(option, true); - } else { - setOptionValue(option, value); - } - } else { - setOptionValue(option, true); - } - }; - } - } - - enum OptionCategories { - MODULAR, - PROPERTY, - PLATFORM_MAC, - PLATFORM_WIN, - PLATFORM_LINUX; - } - - public boolean processArguments() { - try { - // parse cmd line - String arg; - CLIOptions option; - for (; CLIOptions.hasNextArg(); CLIOptions.nextArg()) { - arg = CLIOptions.getArg(); - if ((option = toCLIOption(arg)) != null) { - // found a CLI option - allOptions.add(option); - option.execute(); - } else { - throw new PackagerException("ERR_InvalidOption", arg); - } - } - - // display error for arguments that are not supported - // for current configuration. - - validateArguments(); - - List> launchersAsMap = - new ArrayList<>(); - - for (AddLauncherArguments sl : addLaunchers) { - launchersAsMap.add(sl.getLauncherMap()); - } - - deployParams.addBundleArgument( - StandardBundlerParam.ADD_LAUNCHERS.getID(), - launchersAsMap); - - // at this point deployParams should be already configured - - deployParams.validate(); - - BundleParams bp = deployParams.getBundleParams(); - - // validate name(s) - ArrayList usedNames = new ArrayList(); - usedNames.add(bp.getName()); // add main app name - - for (AddLauncherArguments sl : addLaunchers) { - Map slMap = sl.getLauncherMap(); - String slName = - (String) slMap.get(Arguments.CLIOptions.NAME.getId()); - if (slName == null) { - throw new PackagerException("ERR_NoAddLauncherName"); - } - // same rules apply to additional launcher names as app name - DeployParams.validateName(slName, false); - for (String usedName : usedNames) { - if (slName.equals(usedName)) { - throw new PackagerException("ERR_NoUniqueName"); - } - } - usedNames.add(slName); - } - - generateBundle(bp.getBundleParamsAsMap()); - return true; - } catch (Exception e) { - Log.verbose(e); - String msg1 = e.getMessage(); - Log.fatalError(msg1); - if (e.getCause() != null && e.getCause() != e) { - String msg2 = e.getCause().getMessage(); - if (msg2 != null && !msg1.contains(msg2)) { - Log.fatalError(msg2); - } - } - return false; - } - } - - private void validateArguments() throws PackagerException { - String type = deployParams.getTargetFormat(); - String ptype = (type != null) ? type : "default"; - boolean imageOnly = deployParams.isTargetAppImage(); - boolean hasAppImage = allOptions.contains( - CLIOptions.PREDEFINED_APP_IMAGE); - boolean hasRuntime = allOptions.contains( - CLIOptions.PREDEFINED_RUNTIME_IMAGE); - boolean installerOnly = !imageOnly && hasAppImage; - boolean isMac = OperatingSystem.isMacOS(); - runtimeInstaller = !imageOnly && hasRuntime && !hasAppImage && - !hasMainModule && !hasMainJar; - - for (CLIOptions option : allOptions) { - if (!ValidOptions.checkIfSupported(option)) { - // includes option valid only on different platform - throw new PackagerException("ERR_UnsupportedOption", - option.getIdWithPrefix()); - } - if ((imageOnly && !isMac) || (imageOnly && !hasAppImage && isMac)) { - if (!ValidOptions.checkIfImageSupported(option)) { - throw new PackagerException("ERR_InvalidTypeOption", - option.getIdWithPrefix(), type); - } - } else if (imageOnly && hasAppImage && isMac) { // Signing app image - if (!ValidOptions.checkIfSigningSupported(option)) { - throw new PackagerException( - "ERR_InvalidOptionWithAppImageSigning", - option.getIdWithPrefix()); - } - } else if (installerOnly || runtimeInstaller) { - if (!ValidOptions.checkIfInstallerSupported(option)) { - if (runtimeInstaller) { - throw new PackagerException("ERR_NoInstallerEntryPoint", - option.getIdWithPrefix()); - } else { - throw new PackagerException("ERR_InvalidTypeOption", - option.getIdWithPrefix(), ptype); - } - } - } - } - if (hasRuntime) { - if (hasAppImage) { - // note --runtime-image is only for image or runtime installer. - throw new PackagerException("ERR_MutuallyExclusiveOptions", - CLIOptions.PREDEFINED_RUNTIME_IMAGE.getIdWithPrefix(), - CLIOptions.PREDEFINED_APP_IMAGE.getIdWithPrefix()); - } - if (allOptions.contains(CLIOptions.ADD_MODULES)) { - throw new PackagerException("ERR_MutuallyExclusiveOptions", - CLIOptions.PREDEFINED_RUNTIME_IMAGE.getIdWithPrefix(), - CLIOptions.ADD_MODULES.getIdWithPrefix()); - } - if (allOptions.contains(CLIOptions.JLINK_OPTIONS)) { - throw new PackagerException("ERR_MutuallyExclusiveOptions", - CLIOptions.PREDEFINED_RUNTIME_IMAGE.getIdWithPrefix(), - CLIOptions.JLINK_OPTIONS.getIdWithPrefix()); - } - } - if (allOptions.contains(CLIOptions.MAC_SIGNING_KEY_NAME) && - allOptions.contains(CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY)) { - throw new PackagerException("ERR_MutuallyExclusiveOptions", - CLIOptions.MAC_SIGNING_KEY_NAME.getIdWithPrefix(), - CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getIdWithPrefix()); - } - if (allOptions.contains(CLIOptions.MAC_SIGNING_KEY_NAME) && - allOptions.contains(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY)) { - throw new PackagerException("ERR_MutuallyExclusiveOptions", - CLIOptions.MAC_SIGNING_KEY_NAME.getIdWithPrefix(), - CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getIdWithPrefix()); - } - if (isMac && (imageOnly || "dmg".equals(type)) && - allOptions.contains(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY)) { - throw new PackagerException("ERR_InvalidTypeOption", - CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getIdWithPrefix(), - type); - } - if (allOptions.contains(CLIOptions.DMG_CONTENT) - && !("dmg".equals(type))) { - throw new PackagerException("ERR_InvalidTypeOption", - CLIOptions.DMG_CONTENT.getIdWithPrefix(), ptype); - } - if (hasMainJar && hasMainModule) { - throw new PackagerException("ERR_BothMainJarAndModule"); - } - if (imageOnly && !hasAppImage && !hasMainJar && !hasMainModule) { - throw new PackagerException("ERR_NoEntryPoint"); - } - } - - private jdk.jpackage.internal.Bundler getPlatformBundler() { - boolean appImage = deployParams.isTargetAppImage(); - String type = deployParams.getTargetFormat(); - String bundleType = (appImage ? "IMAGE" : "INSTALLER"); - - for (jdk.jpackage.internal.Bundler bundler : - Bundlers.createBundlersInstance().getBundlers(bundleType)) { - if (type == null) { - if (bundler.isDefault()) { - return bundler; - } - } else { - if (appImage || type.equalsIgnoreCase(bundler.getID())) { - return bundler; - } - } - } - return null; - } - - private void generateBundle(Map params) - throws PackagerException { - - // the temp dir needs to be fetched from the params early, - // to prevent each copy of the params (such as may be used for - // additional launchers) from generating a separate temp dir when - // the default is used (the default is a new temp directory) - // The bundler.cleanup() below would not otherwise be able to - // clean these extra (and unneeded) temp directories. - StandardBundlerParam.TEMP_ROOT.fetchFrom(params); - - // determine what bundler to run - jdk.jpackage.internal.Bundler bundler = getPlatformBundler(); - - if (bundler == null || !bundler.supported(runtimeInstaller)) { - String type = Optional.ofNullable(bundler).map(Bundler::getID).orElseGet( - () -> deployParams.getTargetFormat()); - throw new PackagerException("ERR_InvalidInstallerType", type); - } - - Map localParams = new HashMap<>(params); - try { - Path result = executeBundler(bundler, params, localParams); - if (result == null) { - throw new PackagerException("MSG_BundlerFailed", - bundler.getID(), bundler.getName()); - } - Log.verbose(MessageFormat.format( - I18N.getString("message.bundle-created"), - bundler.getName())); - } catch (ConfigException e) { - Log.verbose(e); - if (e.getAdvice() != null) { - throw new PackagerException(e, "MSG_BundlerConfigException", - bundler.getName(), e.getMessage(), e.getAdvice()); - } else { - throw new PackagerException(e, - "MSG_BundlerConfigExceptionNoAdvice", - bundler.getName(), e.getMessage()); - } - } catch (RuntimeException re) { - Log.verbose(re); - throw new PackagerException(re, "MSG_BundlerRuntimeException", - bundler.getName(), re.toString()); - } finally { - if (userProvidedBuildRoot) { - Log.verbose(MessageFormat.format( - I18N.getString("message.debug-working-directory"), - (Path.of(buildRoot)).toAbsolutePath().toString())); - } else { - // always clean up the temporary directory created - // when --temp option not used. - bundler.cleanup(localParams); - } - } - } - - private static Path executeBundler(Bundler bundler, Map params, - Map localParams) throws ConfigException, PackagerException { - try { - bundler.validate(localParams); - return bundler.execute(localParams, StandardBundlerParam.OUTPUT_DIR.fetchFrom(params)); - } catch (ConfigException|PackagerException ex) { - throw ex; - } catch (RuntimeException ex) { - if (ex.getCause() instanceof ConfigException cfgEx) { - throw cfgEx; - } else if (ex.getCause() instanceof PackagerException pkgEx) { - throw pkgEx; - } else { - throw ex; - } - } - } - - static CLIOptions toCLIOption(String arg) { - CLIOptions option; - if ((option = argIds.get(arg)) == null) { - option = argShortIds.get(arg); - } - return option; - } - - static Map getPropertiesFromFile(String filename) { - Map map = new HashMap<>(); - // load properties file - Properties properties = new Properties(); - try (Reader reader = Files.newBufferedReader(Path.of(filename))) { - properties.load(reader); - } catch (IOException e) { - Log.error("Exception: " + e.getMessage()); - } - - for (final String name: properties.stringPropertyNames()) { - map.put(name, properties.getProperty(name)); - } - - return map; - } - - static List getArgumentList(String inputString) { - List list = new ArrayList<>(); - if (inputString == null || inputString.isEmpty()) { - return list; - } - - // The "pattern" regexp attempts to abide to the rule that - // strings are delimited by whitespace unless surrounded by - // quotes, then it is anything (including spaces) in the quotes. - Matcher m = pattern.matcher(inputString); - while (m.find()) { - String s = inputString.substring(m.start(), m.end()).trim(); - // Ensure we do not have an empty string. trim() will take care of - // whitespace only strings. The regex preserves quotes and escaped - // chars so we need to clean them before adding to the List - if (!s.isEmpty()) { - list.add(unquoteIfNeeded(s)); - } - } - return list; - } - - static void putUnlessNull(Map params, - String param, Object value) { - if (value != null) { - params.put(param, value); - } - } - - private static String unquoteIfNeeded(String in) { - if (in == null) { - return null; - } - - if (in.isEmpty()) { - return ""; - } - - // Use code points to preserve non-ASCII chars - StringBuilder sb = new StringBuilder(); - int codeLen = in.codePointCount(0, in.length()); - int quoteChar = -1; - for (int i = 0; i < codeLen; i++) { - int code = in.codePointAt(i); - if (code == '"' || code == '\'') { - // If quote is escaped make sure to copy it - if (i > 0 && in.codePointAt(i - 1) == '\\') { - sb.deleteCharAt(sb.length() - 1); - sb.appendCodePoint(code); - continue; - } - if (quoteChar != -1) { - if (code == quoteChar) { - // close quote, skip char - quoteChar = -1; - } else { - sb.appendCodePoint(code); - } - } else { - // opening quote, skip char - quoteChar = code; - } - } else { - sb.appendCodePoint(code); - } - } - return sb.toString(); - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BasicBundlers.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BasicBundlers.java deleted file mode 100644 index 7f444fe7337..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BasicBundlers.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.ServiceLoader; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * BasicBundlers - * - * A basic bundlers collection that loads the default bundlers. - * Loads the common bundlers. - *

      - *
    • Windows file image
    • - *
    • Mac .app
    • - *
    • Linux file image
    • - *
    • Windows MSI
    • - *
    • Windows EXE
    • - *
    • Mac DMG
    • - *
    • Mac PKG
    • - *
    • Linux DEB
    • - *
    • Linux RPM
    • - * - *
    - */ -public class BasicBundlers implements Bundlers { - - boolean defaultsLoaded = false; - - private final Collection bundlers = new CopyOnWriteArrayList<>(); - - @Override - public Collection getBundlers() { - return Collections.unmodifiableCollection(bundlers); - } - - @Override - public Collection getBundlers(String type) { - if (type == null) return Collections.emptySet(); - switch (type) { - case "NONE": - return Collections.emptySet(); - case "ALL": - return getBundlers(); - default: - return Arrays.asList(getBundlers().stream() - .filter(b -> type.equalsIgnoreCase(b.getBundleType())) - .toArray(Bundler[]::new)); - } - } - - // Loads bundlers from the META-INF/services direct - @Override - public void loadBundlersFromServices(ClassLoader cl) { - ServiceLoader loader = ServiceLoader.load(Bundler.class, cl); - for (Bundler aLoader : loader) { - bundlers.add(aLoader); - } - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index ba70913eca9..17b805b8259 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -24,14 +24,13 @@ */ package jdk.jpackage.internal; -import java.io.IOException; -import java.nio.file.Files; +import static jdk.jpackage.internal.cli.StandardValidator.IS_DIRECTORY_EMPTY_OR_NON_EXISTENT_PREDICATE; + import java.nio.file.Path; import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.resources.ResourceLocator; @@ -41,20 +40,12 @@ final class BuildEnvBuilder { this.root = Objects.requireNonNull(root); } - BuildEnv create() throws ConfigException { - var exceptionBuilder = I18N.buildConfigException("ERR_BuildRootInvalid", root); - if (Files.isDirectory(root)) { - try (var rootDirContents = Files.list(root)) { - if (rootDirContents.findAny().isPresent()) { - // The root directory is not empty. - throw exceptionBuilder.create(); - } - } catch (IOException ioe) { - throw exceptionBuilder.cause(ioe).create(); - } - } else if (Files.exists(root)) { - // The root is not a directory. - throw exceptionBuilder.create(); + BuildEnv create() { + // The directory should be validated earlier with a proper error message. + // Here is only a sanity check. + if (!IS_DIRECTORY_EMPTY_OR_NON_EXISTENT_PREDICATE.test(root)) { + throw new UnsupportedOperationException( + String.format("Root work directory [%s] should be empty or non existent", root)); } return BuildEnv.create(root, Optional.ofNullable(resourceDir), verbose, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromOptions.java new file mode 100644 index 00000000000..8faabe97a3d --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromOptions.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal; + +import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_RUNTIME_IMAGE; +import static jdk.jpackage.internal.cli.StandardOption.RESOURCE_DIR; +import static jdk.jpackage.internal.cli.StandardOption.TEMP_ROOT; +import static jdk.jpackage.internal.cli.StandardOption.VERBOSE; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.RuntimeLayout; + +final class BuildEnvFromOptions { + + BuildEnvFromOptions() { + predefinedRuntimeImageLayout(RuntimeLayout.DEFAULT); + } + + BuildEnvFromOptions predefinedAppImageLayout(Function v) { + predefinedAppImageLayout = v; + return this; + } + + BuildEnvFromOptions predefinedAppImageLayout(ApplicationLayout v) { + return predefinedAppImageLayout(path -> v.resolveAt(path)); + } + + BuildEnvFromOptions predefinedRuntimeImageLayout(Function v) { + predefinedRuntimeImageLayout = v; + return this; + } + + BuildEnvFromOptions predefinedRuntimeImageLayout(RuntimeLayout v) { + return predefinedRuntimeImageLayout(path -> v.resolveAt(path)); + } + + BuildEnv create(Options options, Application app) { + return create(options, app, Optional.empty()); + } + + BuildEnv create(Options options, Package pkg) { + return create(options, pkg.app(), Optional.of(pkg)); + } + + private BuildEnv create(Options options, Application app, Optional pkg) { + Objects.requireNonNull(options); + Objects.requireNonNull(app); + Objects.requireNonNull(pkg); + Objects.requireNonNull(predefinedAppImageLayout); + Objects.requireNonNull(predefinedRuntimeImageLayout); + + final var builder = new BuildEnvBuilder(TEMP_ROOT.getFrom(options)); + + RESOURCE_DIR.ifPresentIn(options, builder::resourceDir); + VERBOSE.ifPresentIn(options, builder::verbose); + + if (app.isRuntime()) { + var path = PREDEFINED_RUNTIME_IMAGE.getFrom(options); + builder.appImageLayout(predefinedRuntimeImageLayout.apply(path)); + } else if (PREDEFINED_APP_IMAGE.containsIn(options)) { + var path = PREDEFINED_APP_IMAGE.getFrom(options); + builder.appImageLayout(predefinedAppImageLayout.apply(path)); + } else { + pkg.ifPresentOrElse(builder::appImageDirFor, () -> { + builder.appImageDirFor(app); + }); + } + + return builder.create(); + } + + private Function predefinedAppImageLayout; + private Function predefinedRuntimeImageLayout; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java deleted file mode 100644 index 6fb1a342fbf..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.jpackage.internal; - -import static jdk.jpackage.internal.ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; -import static jdk.jpackage.internal.StandardBundlerParam.VERBOSE; - -import java.nio.file.Path; -import java.util.Map; -import java.util.function.Function; -import jdk.jpackage.internal.model.ApplicationLayout; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.RuntimeLayout; - -final class BuildEnvFromParams { - - static BuildEnv create(Map params, - Function predefinedAppImageLayoutProvider, - Function predefinedRuntimeImageLayoutProvider) throws ConfigException { - - final var builder = new BuildEnvBuilder(TEMP_ROOT.fetchFrom(params)); - - RESOURCE_DIR.copyInto(params, builder::resourceDir); - VERBOSE.copyInto(params, builder::verbose); - - final var app = FromParams.APPLICATION.findIn(params).orElseThrow(); - - final var pkg = FromParams.getCurrentPackage(params); - - if (app.isRuntime()) { - var layout = predefinedRuntimeImageLayoutProvider.apply(PREDEFINED_RUNTIME_IMAGE.findIn(params).orElseThrow()); - builder.appImageLayout(layout); - } else if (StandardBundlerParam.hasPredefinedAppImage(params)) { - var layout = predefinedAppImageLayoutProvider.apply(PREDEFINED_APP_IMAGE.findIn(params).orElseThrow()); - builder.appImageLayout(layout); - } else if (pkg.isPresent()) { - builder.appImageDirFor(pkg.orElseThrow()); - } else { - builder.appImageDirFor(app); - } - - return builder.create(); - } - - static final BundlerParamInfo BUILD_ENV = BundlerParamInfo.createBundlerParam(BuildEnv.class, params -> { - return create(params, PLATFORM_APPLICATION_LAYOUT::resolveAt, RuntimeLayout.DEFAULT::resolveAt); - }); -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundleParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundleParams.java deleted file mode 100644 index 937a3655e8b..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundleParams.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2012, 2022, 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 jdk.jpackage.internal; - -import java.util.HashMap; -import java.util.Map; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; - -public class BundleParams { - - protected final Map params; - - /** - * create a new bundle with all default values - */ - public BundleParams() { - params = new HashMap<>(); - } - - /** - * Create a bundle params with a copy of the params - * @param params map of initial parameters to be copied in. - */ - public BundleParams(Map params) { - this.params = new HashMap<>(params); - } - - public void addAllBundleParams(Map params) { - this.params.putAll(params); - } - - // NOTE: we do not care about application parameters here - // as they will be embedded into jar file manifest and - // java launcher will take care of them! - - public Map getBundleParamsAsMap() { - return new HashMap<>(params); - } - - public String getName() { - return APP_NAME.fetchFrom(params); - } - - private void putUnlessNull(String param, Object value) { - if (value != null) { - params.put(param, value); - } - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java deleted file mode 100644 index 0d29677e826..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundler.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2014, 2025, 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 jdk.jpackage.internal; - -import java.nio.file.Path; -import java.util.Map; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.PackagerException; - -/** - * Bundler - * - * The basic interface implemented by all Bundlers. - */ -public interface Bundler { - /** - * @return User Friendly name of this bundler. - */ - String getName(); - - /** - * @return Command line identifier of the bundler. Should be unique. - */ - String getID(); - - /** - * @return The bundle type of the bundle that is created by this bundler. - */ - String getBundleType(); - - /** - * Determines if this bundler will execute with the given parameters. - * - * @param params The parameters to be validate. Validation may modify - * the map, so if you are going to be using the same map - * across multiple bundlers you should pass in a deep copy. - * @return true if valid - * @throws ConfigException If the configuration params are incorrect. The - * exception may contain advice on how to modify the params map - * to make it valid. - */ - public boolean validate(Map params) - throws ConfigException; - - /** - * Creates a bundle from existing content. - * - * If a call to {@link #validate(java.util.Map)} date} returns true with - * the parameters map, then you can expect a valid output. - * However if an exception was thrown out of validate or it returned - * false then you should not expect sensible results from this call. - * It may or may not return a value, and it may or may not throw an - * exception. But any output should not be considered valid or sane. - * - * @param params The Bundle parameters, - * Keyed by the id from the ParamInfo. Execution may - * modify the map, so if you are going to be using the - * same map across multiple bundlers you should pass - * in a deep copy. - * @param outputParentDir - * The parent dir that the returned bundle will be placed in. - * @return The resulting bundled file - * - * For a bundler that produces a single artifact file this will be the - * location of that artifact (.exe file, .deb file, etc) - * - * For a bundler that produces a specific directory format output this will - * be the location of that specific directory (.app file, etc). - * - * For a bundler that produce multiple files, this will be a parent - * directory of those files (linux and windows images), whose name is not - * relevant to the result. - * - * @throws java.lang.IllegalArgumentException for any of the following - * reasons: - *
      - *
    • A required parameter is not found in the params list, for - * example missing the main class.
    • - *
    • A parameter has the wrong type of an object, for example a - * String where a File is required
    • - *
    • Bundler specific incompatibilities with the parameters, for - * example a bad version number format or an application id with - * forward slashes.
    • - *
    - */ - public Path execute(Map params, - Path outputParentDir) throws PackagerException; - - /** - * Removes temporary files that are used for bundling. - */ - public void cleanup(Map params); - - /** - * Returns "true" if this bundler is supported on current platform. - */ - public boolean supported(boolean runtimeInstaller); - - /** - * Returns "true" if this bundler is he default for the current platform. - */ - public boolean isDefault(); -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java deleted file mode 100644 index 81030b18f6d..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2014, 2025, 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 jdk.jpackage.internal; - -import java.nio.file.Path; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Function; -import jdk.jpackage.internal.util.function.ThrowingFunction; - -/** - * BundlerParamInfo - * - * A BundlerParamInfo encapsulates an individual bundler parameter of type . - * - * @param id The command line and hashmap name of the parameter - * - * @param valueType Type of the parameter - * - * @param defaultValueFunction If the value is not set, and no fallback value is found, the - * parameter uses the value returned by the producer. - * - * @param stringConverter An optional string converter for command line arguments. - */ -record BundlerParamInfo(String id, Class valueType, - Function, T> defaultValueFunction, - BiFunction, T> stringConverter) { - - BundlerParamInfo { - Objects.requireNonNull(id); - Objects.requireNonNull(valueType); - } - - static BundlerParamInfo createStringBundlerParam(String id) { - return new BundlerParamInfo<>(id, String.class, null, null); - } - - static BundlerParamInfo createBooleanBundlerParam(String id) { - return new BundlerParamInfo<>(id, Boolean.class, null, BundlerParamInfo::toBoolean); - } - - static BundlerParamInfo createPathBundlerParam(String id) { - return new BundlerParamInfo<>(id, Path.class, null, BundlerParamInfo::toPath); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - static BundlerParamInfo createBundlerParam(String id, Class valueType, - ThrowingFunction, U> valueCtor) { - return new BundlerParamInfo(id, valueType, ThrowingFunction.toFunction(valueCtor), null); - } - - static BundlerParamInfo createBundlerParam(Class valueType, - ThrowingFunction, U> valueCtor) { - return createBundlerParam(valueType.getName(), valueType, valueCtor); - } - - static boolean toBoolean(String value, Map params) { - if (value == null || "null".equalsIgnoreCase(value)) { - return false; - } else { - return Boolean.valueOf(value); - } - } - - static Path toPath(String value, Map params) { - return Path.of(value); - } - - String getID() { - return id; - } - - Class getValueType() { - return valueType; - } - - /** - * Returns true if value was not provided on command line for this parameter. - * - * @param params - params from which value will be fetch - * @return true if value was not provided on command line, false otherwise - */ - boolean getIsDefaultValue(Map params) { - Object o = params.get(getID()); - if (o != null) { - return false; // We have user provided value - } - - if (params.containsKey(getID())) { - return false; // explicit nulls are allowed for provided value - } - - return true; - } - - Function, T> getDefaultValueFunction() { - return defaultValueFunction; - } - - BiFunction, T> getStringConverter() { - return stringConverter; - } - - final T fetchFrom(Map params) { - return fetchFrom(params, true); - } - - @SuppressWarnings("unchecked") - final T fetchFrom(Map params, - boolean invokeDefault) { - Object o = params.get(getID()); - if (o instanceof String && getStringConverter() != null) { - return getStringConverter().apply((String) o, params); - } - - Class klass = getValueType(); - if (klass.isInstance(o)) { - return (T) o; - } - if (o != null) { - throw new IllegalArgumentException("Param " + getID() - + " should be of type " + getValueType() - + " but is a " + o.getClass()); - } - if (params.containsKey(getID())) { - // explicit nulls are allowed - return null; - } - - if (invokeDefault && (getDefaultValueFunction() != null)) { - T result = getDefaultValueFunction().apply(params); - if (result != null) { - params.put(getID(), result); - } - return result; - } - - // ultimate fallback - return null; - } - - Optional findIn(Map params) { - if (params.containsKey(getID())) { - return Optional.of(fetchFrom(params, true)); - } else { - return Optional.empty(); - } - } - - void copyInto(Map params, Consumer consumer) { - findIn(params).ifPresent(consumer); - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundlers.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundlers.java deleted file mode 100644 index 955952d563d..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Bundlers.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal; - -import java.util.Collection; -import java.util.Iterator; -import java.util.ServiceLoader; - -/** - * Bundlers - * - * The interface implemented by BasicBundlers - */ -public interface Bundlers { - - /** - * This convenience method will call - * {@link #createBundlersInstance(ClassLoader)} - * with the classloader that this Bundlers is loaded from. - * - * @return an instance of Bundlers loaded and configured from - * the current ClassLoader. - */ - public static Bundlers createBundlersInstance() { - return createBundlersInstance(Bundlers.class.getClassLoader()); - } - - /** - * This convenience method will automatically load a Bundlers instance - * from either META-INF/services or the default - * {@link BasicBundlers} if none are found in - * the services meta-inf. - * - * After instantiating the bundlers instance it will load the default - * bundlers via {@link #loadDefaultBundlers()} as well as requesting - * the services loader to load any other bundelrs via - * {@link #loadBundlersFromServices(ClassLoader)}. - - * - * @param servicesClassLoader the classloader to search for - * META-INF/service registered bundlers - * @return an instance of Bundlers loaded and configured from - * the specified ClassLoader - */ - public static Bundlers createBundlersInstance( - ClassLoader servicesClassLoader) { - ServiceLoader bundlersLoader = - ServiceLoader.load(Bundlers.class, servicesClassLoader); - Bundlers bundlers = null; - Iterator iter = bundlersLoader.iterator(); - if (iter.hasNext()) { - bundlers = iter.next(); - } - if (bundlers == null) { - bundlers = new BasicBundlers(); - } - - bundlers.loadBundlersFromServices(servicesClassLoader); - return bundlers; - } - - /** - * Returns all of the preconfigured, requested, and manually - * configured bundlers loaded with this instance. - * - * @return a read-only collection of the requested bundlers - */ - Collection getBundlers(); - - /** - * Returns all of the preconfigured, requested, and manually - * configured bundlers loaded with this instance that are of - * a specific BundleType, such as disk images, installers, or - * remote installers. - * - * @return a read-only collection of the requested bundlers - */ - Collection getBundlers(String type); - - /** - * Loads bundlers from the META-INF/services directly. - * - * This method is called from the - * {@link #createBundlersInstance(ClassLoader)} - * and {@link #createBundlersInstance()} methods. - */ - void loadBundlersFromServices(ClassLoader cl); - -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CLIHelp.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CLIHelp.java deleted file mode 100644 index 7790ebb3ebb..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CLIHelp.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2018, 2025, 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 jdk.jpackage.internal; - -import jdk.internal.util.OperatingSystem; - -import java.util.ResourceBundle; -import java.io.File; -import java.text.MessageFormat; - - -/** - * CLIHelp - * - * Generate and show the command line interface help message(s). - */ -public class CLIHelp { - - private static final ResourceBundle I18N = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.HelpResources"); - - // generates --help for jpackage's CLI - public static void showHelp(boolean noArgs) { - - if (noArgs) { - Log.info(I18N.getString("MSG_Help_no_args")); - } else { - OperatingSystem platform = OperatingSystem.current(); - String types; - String pLaunchOptions; - String pInstallOptions; - String pInstallDir; - String pAppImageDescription; - String pSignSampleUsage; - String pAppContentNote; - switch (platform) { - case MACOS: - types = "{\"app-image\", \"dmg\", \"pkg\"}"; - pLaunchOptions = I18N.getString("MSG_Help_mac_launcher"); - pInstallOptions = I18N.getString("MSG_Help_mac_install"); - pInstallDir - = I18N.getString("MSG_Help_mac_linux_install_dir"); - pAppImageDescription - = I18N.getString("MSG_Help_mac_app_image"); - pSignSampleUsage - = I18N.getString("MSG_Help_mac_sign_sample_usage"); - pAppContentNote - = I18N.getString("MSG_Help_mac_app_content_note"); - break; - case LINUX: - types = "{\"app-image\", \"rpm\", \"deb\"}"; - pLaunchOptions = ""; - pInstallOptions = I18N.getString("MSG_Help_linux_install"); - pInstallDir - = I18N.getString("MSG_Help_mac_linux_install_dir"); - pAppImageDescription - = I18N.getString("MSG_Help_default_app_image"); - pSignSampleUsage = ""; - pAppContentNote = ""; - break; - case WINDOWS: - types = "{\"app-image\", \"exe\", \"msi\"}"; - pLaunchOptions = I18N.getString("MSG_Help_win_launcher"); - pInstallOptions = I18N.getString("MSG_Help_win_install"); - pInstallDir - = I18N.getString("MSG_Help_win_install_dir"); - pAppImageDescription - = I18N.getString("MSG_Help_default_app_image"); - pSignSampleUsage = ""; - pAppContentNote = ""; - break; - default: - types = "{\"app-image\", \"exe\", \"msi\", \"rpm\", \"deb\", \"pkg\", \"dmg\"}"; - pLaunchOptions = I18N.getString("MSG_Help_win_launcher") - + I18N.getString("MSG_Help_mac_launcher"); - pInstallOptions = I18N.getString("MSG_Help_win_install") - + I18N.getString("MSG_Help_linux_install") - + I18N.getString("MSG_Help_mac_install"); - pInstallDir - = I18N.getString("MSG_Help_default_install_dir"); - pAppImageDescription - = I18N.getString("MSG_Help_default_app_image"); - pSignSampleUsage = ""; - pAppContentNote = ""; - break; - } - Log.info(MessageFormat.format(I18N.getString("MSG_Help"), - File.pathSeparator, types, pLaunchOptions, - pInstallOptions, pInstallDir, pAppImageDescription, - pSignSampleUsage, pAppContentNote)); - } - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java index 6b4ba3c4410..9cb9fb5cba0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CfgFile.java @@ -30,7 +30,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Optional; +import java.util.Objects; import java.util.stream.Stream; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; @@ -47,10 +47,14 @@ final class CfgFile { CfgFile(Application app, Launcher launcher) { startupInfo = launcher.startupInfo().orElseThrow(); outputFileName = launcher.executableName() + ".cfg"; - version = app.version(); + version = Objects.requireNonNull(app.version()); } void create(ApplicationLayout appLayout) throws IOException { + Objects.requireNonNull(appLayout); + + Objects.requireNonNull(startupInfo.qualifiedClassName()); + List> content = new ArrayList<>(); final var refs = new Referencies(appLayout); @@ -58,7 +62,7 @@ final class CfgFile { content.add(Map.entry("[Application]", SECTION_TAG)); if (startupInfo instanceof LauncherModularStartupInfo modularStartupInfo) { - content.add(Map.entry("app.mainmodule", modularStartupInfo.moduleName() + content.add(Map.entry("app.mainmodule", Objects.requireNonNull(modularStartupInfo.moduleName()) + "/" + startupInfo.qualifiedClassName())); } else if (startupInfo instanceof LauncherJarStartupInfo jarStartupInfo) { Path mainJarPath = refs.appDirectory().resolve(jarStartupInfo.jarPath()); @@ -67,16 +71,13 @@ final class CfgFile { content.add(Map.entry("app.mainjar", mainJarPath)); } else { content.add(Map.entry("app.classpath", mainJarPath)); - } - - if (!jarStartupInfo.isJarWithMainClass()) { content.add(Map.entry("app.mainclass", startupInfo.qualifiedClassName())); } } else { throw new UnsupportedOperationException(); } - for (var value : Optional.ofNullable(startupInfo.classPath()).orElseGet(List::of)) { + for (var value : startupInfo.classPath()) { content.add(Map.entry("app.classpath", refs.appDirectory().resolve(value).toString())); } @@ -88,7 +89,7 @@ final class CfgFile { "java-options", "-Djpackage.app-version=" + version)); // add user supplied java options if there are any - for (var value : Optional.ofNullable(startupInfo.javaOptions()).orElseGet(List::of)) { + for (var value : startupInfo.javaOptions()) { content.add(Map.entry("java-options", value)); } @@ -98,7 +99,7 @@ final class CfgFile { content.add(Map.entry("java-options", refs.appModsDirectory())); } - var arguments = Optional.ofNullable(startupInfo.defaultParameters()).orElseGet(List::of); + var arguments = startupInfo.defaultParameters(); if (!arguments.isEmpty()) { content.add(Map.entry("[ArgOptions]", SECTION_TAG)); for (var value : arguments) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java new file mode 100644 index 00000000000..0bf7d6f41b2 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal; + +import static java.util.stream.Collectors.toMap; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.cli.CliBundlingEnvironment; +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.cli.StandardBundlingOperation; +import jdk.jpackage.internal.model.AppImagePackageType; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.BundlingOperationDescriptor; +import jdk.jpackage.internal.model.JPackageException; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.StandardPackageType; +import jdk.jpackage.internal.util.Result; + +class DefaultBundlingEnvironment implements CliBundlingEnvironment { + + DefaultBundlingEnvironment(Builder builder) { + this(Optional.ofNullable(builder.defaultOperationSupplier), builder.bundlers); + } + + DefaultBundlingEnvironment(Optional>> defaultOperationSupplier, + Map>>> bundlers) { + + this.bundlers = bundlers.entrySet().stream().collect(toMap(Map.Entry::getKey, e -> { + return new CachingSupplier<>(e.getValue()); + })); + + this.defaultOperationSupplier = Objects.requireNonNull(defaultOperationSupplier).map(CachingSupplier::new); + } + + + static final class Builder { + + Builder defaultOperation(Supplier> v) { + defaultOperationSupplier = v; + return this; + } + + Builder defaultOperation(StandardBundlingOperation v) { + return defaultOperation(() -> Optional.of(v.descriptor())); + } + + Builder bundler(StandardBundlingOperation op, Supplier>> bundlerSupplier) { + bundlers.put(Objects.requireNonNull(op.descriptor()), Objects.requireNonNull(bundlerSupplier)); + return this; + } + + Builder bundler(StandardBundlingOperation op, + Supplier> sysEnvResultSupplier, BiConsumer bundler) { + return bundler(op, createBundlerSupplier(sysEnvResultSupplier, bundler)); + } + + Builder bundler(StandardBundlingOperation op, Consumer bundler) { + Objects.requireNonNull(bundler); + return bundler(op, () -> Result.ofValue(bundler)); + } + + private Supplier> defaultOperationSupplier; + private final Map>>> bundlers = new HashMap<>(); + } + + + static Builder build() { + return new Builder(); + } + + static Supplier>> createBundlerSupplier( + Supplier> sysEnvResultSupplier, BiConsumer bundler) { + Objects.requireNonNull(sysEnvResultSupplier); + Objects.requireNonNull(bundler); + return () -> { + return sysEnvResultSupplier.get().map(sysEnv -> { + return options -> { + bundler.accept(options, sysEnv); + }; + }); + }; + } + + static void createApplicationImage(Options options, Application app, PackagingPipeline.Builder pipelineBuilder) { + Objects.requireNonNull(options); + Objects.requireNonNull(app); + Objects.requireNonNull(pipelineBuilder); + + final var outputDir = OptionUtils.outputDir(options).resolve(app.appImageDirName()); + + IOUtils.writableOutputDir(outputDir.getParent()); + + final var env = new BuildEnvFromOptions() + .predefinedAppImageLayout(app.asApplicationLayout().orElseThrow()) + .create(options, app); + + Log.verbose(I18N.format("message.creating-app-bundle", outputDir.getFileName(), outputDir.toAbsolutePath().getParent())); + + if (Files.exists(outputDir)) { + throw new JPackageException(I18N.format("error.root-exists", outputDir.toAbsolutePath())); + } + + pipelineBuilder.excludeDirFromCopying(outputDir.getParent()) + .create().execute(BuildEnv.withAppImageDir(env, outputDir), app); + } + + static void createNativePackage(Options options, + Function createPackage, + BiFunction createBuildEnv, + PackagingPipeline.Builder pipelineBuilder, + Packager.PipelineBuilderMutatorFactory pipelineBuilderMutatorFactory) { + + Objects.requireNonNull(pipelineBuilder); + createNativePackage(options, createPackage, createBuildEnv, _ -> pipelineBuilder, pipelineBuilderMutatorFactory); + } + + static void createNativePackage(Options options, + Function createPackage, + BiFunction createBuildEnv, + Function createPipelineBuilder, + Packager.PipelineBuilderMutatorFactory pipelineBuilderMutatorFactory) { + + Objects.requireNonNull(options); + Objects.requireNonNull(createPackage); + Objects.requireNonNull(createBuildEnv); + Objects.requireNonNull(createPipelineBuilder); + Objects.requireNonNull(pipelineBuilderMutatorFactory); + + var pkg = Objects.requireNonNull(createPackage.apply(options)); + + Packager.build().pkg(pkg) + .outputDir(OptionUtils.outputDir(options)) + .env(Objects.requireNonNull(createBuildEnv.apply(options, pkg))) + .pipelineBuilderMutatorFactory(pipelineBuilderMutatorFactory) + .execute(Objects.requireNonNull(createPipelineBuilder.apply(pkg))); + } + + @Override + public Optional defaultOperation() { + return defaultOperationSupplier.flatMap(Supplier::get); + } + + @Override + public void createBundle(BundlingOperationDescriptor op, Options cmdline) { + final var bundler = getBundlerSupplier(op).get().orElseThrow(); + Optional permanentWorkDirectory = Optional.empty(); + try (var tempDir = new TempDirectory(cmdline)) { + if (!tempDir.deleteOnClose()) { + permanentWorkDirectory = Optional.of(tempDir.path()); + } + bundler.accept(tempDir.options()); + + var packageType = OptionUtils.bundlingOperation(cmdline).packageType(); + + Log.verbose(I18N.format("message.bundle-created", I18N.getString(bundleTypeDescription(packageType, op.os())))); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } finally { + permanentWorkDirectory.ifPresent(workDir -> { + Log.verbose(I18N.format("message.debug-working-directory", workDir.toAbsolutePath())); + }); + } + } + + @Override + public Collection configurationErrors(BundlingOperationDescriptor op) { + return getBundlerSupplier(op).get().errors(); + } + + private Supplier>> getBundlerSupplier(BundlingOperationDescriptor op) { + return Optional.ofNullable(bundlers.get(op)).orElseThrow(NoSuchElementException::new); + } + + private String bundleTypeDescription(PackageType type, OperatingSystem os) { + switch (type) { + case StandardPackageType stdType -> { + switch (stdType) { + case WIN_MSI -> { + return "bundle-type.win-msi"; + } + case WIN_EXE -> { + return "bundle-type.win-exe"; + } + case LINUX_DEB -> { + return "bundle-type.linux-deb"; + } + case LINUX_RPM -> { + return "bundle-type.linux-rpm"; + } + case MAC_DMG -> { + return "bundle-type.mac-dmg"; + } + case MAC_PKG -> { + return "bundle-type.mac-pkg"; + } + default -> { + throw new AssertionError(); + } + } + } + case AppImagePackageType appImageType -> { + switch (os) { + case WINDOWS -> { + return "bundle-type.win-app"; + } + case LINUX -> { + return "bundle-type.linux-app"; + } + case MACOS -> { + return "bundle-type.mac-app"; + } + default -> { + throw new AssertionError(); + } + } + } + default -> { + throw new AssertionError(); + } + } + } + + + private static final class CachingSupplier implements Supplier { + + CachingSupplier(Supplier getter) { + this.getter = Objects.requireNonNull(getter); + } + + @Override + public T get() { + return cachedValue.updateAndGet(v -> { + return Optional.ofNullable(v).orElseGet(getter); + }); + } + + private final Supplier getter; + private final AtomicReference cachedValue = new AtomicReference<>(); + } + + + private final Map>>> bundlers; + private final Optional>> defaultOperationSupplier; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java deleted file mode 100644 index d7b4052d34a..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (c) 2011, 2025, 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 jdk.jpackage.internal; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.InvalidPathException; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Stream; -import jdk.jpackage.internal.model.PackagerException; - -/** - * DeployParams - * - * This class is generated and used in Arguments.processArguments() as - * intermediate step in generating the BundleParams and ultimately the Bundles - */ -public class DeployParams { - - String targetFormat = null; // means default type for this platform - - // raw arguments to the bundler - Map bundlerArguments = new LinkedHashMap<>(); - - static class Template { - Path in; - Path out; - - Template(Path in, Path out) { - this.in = in; - this.out = out; - } - } - - // we need to expand as in some cases - // (most notably jpackage) - // we may get "." as filename and assumption is we include - // everything in the given folder - // (IOUtils.copyfiles() have recursive behavior) - List expandFileset(Path root) throws IOException { - List files = new LinkedList<>(); - if (!Files.isSymbolicLink(root)) { - if (Files.isDirectory(root)) { - try (Stream stream = Files.list(root)) { - List children = stream.toList(); - if (children != null && children.size() > 0) { - children.forEach(f -> { - try { - files.addAll(expandFileset(f)); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - }); - } else { - // Include empty folders - files.add(root); - } - } - } else { - files.add(root); - } - } - return files; - } - - static void validateName(String s, boolean forApp) - throws PackagerException { - - String exceptionKey = forApp ? - "ERR_InvalidAppName" : "ERR_InvalidSLName"; - - if (s == null) { - if (forApp) { - return; - } else { - throw new PackagerException(exceptionKey); - } - } - if (s.length() == 0 || s.charAt(s.length() - 1) == '\\') { - throw new PackagerException(exceptionKey, s); - } - try { - // name must be valid path element for this file system - Path p = Path.of(s); - // and it must be a single name element in a path - if (p.getNameCount() != 1) { - throw new PackagerException(exceptionKey, s); - } - } catch (InvalidPathException ipe) { - throw new PackagerException(ipe, exceptionKey, s); - } - - for (int i = 0; i < s.length(); i++) { - char a = s.charAt(i); - // We check for ASCII codes first which we accept. If check fails, - // check if it is acceptable extended ASCII or unicode character. - if (a < ' ' || a > '~') { - // Accept anything else including special chars like copyright - // symbols. Note: space will be included by ASCII check above, - // but other whitespace like tabs or new line will be rejected. - if (Character.isISOControl(a) || - Character.isWhitespace(a)) { - throw new PackagerException(exceptionKey, s); - } - } else if (a == '"' || a == '%') { - throw new PackagerException(exceptionKey, s); - } - } - } - - @SuppressWarnings("unchecked") - public void validate() throws PackagerException { - boolean hasModule = (bundlerArguments.get( - Arguments.CLIOptions.MODULE.getId()) != null); - boolean hasAppImage = (bundlerArguments.get( - Arguments.CLIOptions.PREDEFINED_APP_IMAGE.getId()) != null); - boolean hasMain = (bundlerArguments.get( - Arguments.CLIOptions.MAIN_JAR.getId()) != null); - boolean hasRuntimeImage = (bundlerArguments.get( - Arguments.CLIOptions.PREDEFINED_RUNTIME_IMAGE.getId()) != null); - boolean hasInput = (bundlerArguments.get( - Arguments.CLIOptions.INPUT.getId()) != null); - boolean hasModulePath = (bundlerArguments.get( - Arguments.CLIOptions.MODULE_PATH.getId()) != null); - boolean hasMacAppStore = (bundlerArguments.get( - Arguments.CLIOptions.MAC_APP_STORE.getId()) != null); - boolean runtimeInstaller = !isTargetAppImage() && - !hasAppImage && !hasModule && !hasMain && hasRuntimeImage; - - if (isTargetAppImage()) { - // Module application requires --runtime-image or --module-path - if (hasModule) { - if (!hasModulePath && !hasRuntimeImage && !hasAppImage) { - throw new PackagerException("ERR_MissingArgument", - "--runtime-image or --module-path"); - } - } else { - if (!hasInput && !hasAppImage) { - throw new PackagerException("error.no-input-parameter"); - } - } - } else { - if (!runtimeInstaller) { - if (hasModule) { - if (!hasModulePath && !hasRuntimeImage && !hasAppImage) { - throw new PackagerException("ERR_MissingArgument", - "--runtime-image, --module-path or --app-image"); - } - } else { - if (!hasInput && !hasAppImage) { - throw new PackagerException("ERR_MissingArgument", - "--input or --app-image"); - } - } - } - } - - // if bundling non-modular image, or installer without app-image - // then we need some resources and a main class - if (!hasModule && !hasAppImage && !runtimeInstaller && !hasMain) { - throw new PackagerException("ERR_MissingArgument", "--main-jar"); - } - - String name = (String)bundlerArguments.get( - Arguments.CLIOptions.NAME.getId()); - validateName(name, true); - - // Validate app image if set - String appImage = (String)bundlerArguments.get( - Arguments.CLIOptions.PREDEFINED_APP_IMAGE.getId()); - if (appImage != null) { - Path appImageDir = Path.of(appImage); - if (!Files.exists(appImageDir) - || appImageDir.toFile().list() == null - || appImageDir.toFile().list().length == 0) { - throw new PackagerException("ERR_AppImageNotExist", appImage); - } - } - - // Validate temp dir - String root = (String)bundlerArguments.get( - Arguments.CLIOptions.TEMP_ROOT.getId()); - if (root != null && Files.exists(Path.of(root))) { - try (Stream stream = Files.walk(Path.of(root), 1)) { - Path [] contents = stream.toArray(Path[]::new); - // contents.length > 1 because Files.walk(path) includes path - if (contents != null && contents.length > 1) { - throw new PackagerException( - "ERR_BuildRootInvalid", root); - } - } catch (IOException ioe) { - throw new PackagerException(ioe); - } - } - - // Validate resource dir - String resources = (String)bundlerArguments.get( - Arguments.CLIOptions.RESOURCE_DIR.getId()); - if (resources != null) { - if (!(Files.exists(Path.of(resources)))) { - throw new PackagerException( - "message.resource-dir-does-not-exist", - Arguments.CLIOptions.RESOURCE_DIR.getId(), resources); - } - } - - // Validate predefined runtime dir - String runtime = (String)bundlerArguments.get( - Arguments.CLIOptions.PREDEFINED_RUNTIME_IMAGE.getId()); - if (runtime != null) { - if (!(Files.exists(Path.of(runtime)))) { - throw new PackagerException( - "message.runtime-image-dir-does-not-exist", - Arguments.CLIOptions.PREDEFINED_RUNTIME_IMAGE.getId(), - runtime); - } - } - - - // Validate license file if set - String license = (String)bundlerArguments.get( - Arguments.CLIOptions.LICENSE_FILE.getId()); - if (license != null) { - if (!(Files.exists(Path.of(license)))) { - throw new PackagerException("ERR_LicenseFileNotExit"); - } - } - - // Validate icon file if set - String icon = (String)bundlerArguments.get( - Arguments.CLIOptions.ICON.getId()); - if (icon != null) { - if (!(Files.exists(Path.of(icon)))) { - throw new PackagerException("ERR_IconFileNotExit", - Path.of(icon).toAbsolutePath().toString()); - } - } - - - if (hasMacAppStore) { - // Validate jlink-options if mac-app-store is set - Object jlinkOptions = bundlerArguments.get( - Arguments.CLIOptions.JLINK_OPTIONS.getId()); - if (jlinkOptions instanceof List) { - List options = (List) jlinkOptions; - if (!options.contains("--strip-native-commands")) { - throw new PackagerException( - "ERR_MissingJLinkOptMacAppStore", - "--strip-native-commands"); - } - } - } - } - - void setTargetFormat(String t) { - targetFormat = t; - } - - String getTargetFormat() { - return targetFormat; - } - - boolean isTargetAppImage() { - return ("app-image".equals(targetFormat)); - } - - private static final Set multi_args = new TreeSet<>(Arrays.asList( - StandardBundlerParam.JAVA_OPTIONS.getID(), - StandardBundlerParam.ARGUMENTS.getID(), - StandardBundlerParam.MODULE_PATH.getID(), - StandardBundlerParam.ADD_MODULES.getID(), - StandardBundlerParam.LIMIT_MODULES.getID(), - StandardBundlerParam.FILE_ASSOCIATIONS.getID(), - StandardBundlerParam.DMG_CONTENT.getID(), - StandardBundlerParam.APP_CONTENT.getID(), - StandardBundlerParam.JLINK_OPTIONS.getID() - )); - - @SuppressWarnings("unchecked") - public void addBundleArgument(String key, Object value) { - // special hack for multi-line arguments - if (multi_args.contains(key)) { - Object existingValue = bundlerArguments.get(key); - if (existingValue instanceof String && value instanceof String) { - String delim = "\n\n"; - if (key.equals(StandardBundlerParam.MODULE_PATH.getID())) { - delim = File.pathSeparator; - } else if ( - key.equals(StandardBundlerParam.DMG_CONTENT.getID()) || - key.equals(StandardBundlerParam.APP_CONTENT.getID()) || - key.equals(StandardBundlerParam.ADD_MODULES.getID())) { - delim = ","; - } - bundlerArguments.put(key, existingValue + delim + value); - } else if (existingValue instanceof List && value instanceof List) { - ((List)existingValue).addAll((List)value); - } else if (existingValue instanceof Map && - value instanceof String && ((String)value).contains("=")) { - String[] mapValues = ((String)value).split("=", 2); - ((Map)existingValue).put(mapValues[0], mapValues[1]); - } else { - bundlerArguments.put(key, value); - } - } else { - bundlerArguments.put(key, value); - } - } - - BundleParams getBundleParams() { - BundleParams bundleParams = new BundleParams(); - - // check for collisions - TreeSet keys = new TreeSet<>(bundlerArguments.keySet()); - keys.retainAll(bundleParams.getBundleParamsAsMap().keySet()); - - if (!keys.isEmpty()) { - throw new RuntimeException("Deploy Params and Bundler Arguments " - + "overlap in the following values:" + keys.toString()); - } - - bundleParams.addAllBundleParams(bundlerArguments); - - return bundleParams; - } - - @Override - public String toString() { - return "DeployParams {" + "output: " + "}"; - } - -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java index 349a09f237c..ed89ffe1ef6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java @@ -111,6 +111,10 @@ final record FileAssociationGroup(List items) { return this; } + Optional description() { + return Optional.ofNullable(description); + } + Builder mimeTypes(Collection v) { mimeTypes = Set.copyOf(v); return this; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java new file mode 100644 index 00000000000..6b74cab4e65 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal; + +import static jdk.jpackage.internal.ApplicationBuilder.normalizeIcons; +import static jdk.jpackage.internal.JLinkRuntimeBuilder.ensureBaseModuleInModulePath; +import static jdk.jpackage.internal.OptionUtils.isRuntimeInstaller; +import static jdk.jpackage.internal.cli.StandardOption.ABOUT_URL; +import static jdk.jpackage.internal.cli.StandardOption.ADDITIONAL_LAUNCHERS; +import static jdk.jpackage.internal.cli.StandardOption.ADD_MODULES; +import static jdk.jpackage.internal.cli.StandardOption.APP_CONTENT; +import static jdk.jpackage.internal.cli.StandardOption.APP_VERSION; +import static jdk.jpackage.internal.cli.StandardOption.COPYRIGHT; +import static jdk.jpackage.internal.cli.StandardOption.DESCRIPTION; +import static jdk.jpackage.internal.cli.StandardOption.INPUT; +import static jdk.jpackage.internal.cli.StandardOption.INSTALL_DIR; +import static jdk.jpackage.internal.cli.StandardOption.JLINK_OPTIONS; +import static jdk.jpackage.internal.cli.StandardOption.LICENSE_FILE; +import static jdk.jpackage.internal.cli.StandardOption.MODULE_PATH; +import static jdk.jpackage.internal.cli.StandardOption.NAME; +import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_RUNTIME_IMAGE; +import static jdk.jpackage.internal.cli.StandardOption.RESOURCE_DIR; +import static jdk.jpackage.internal.cli.StandardOption.VENDOR; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLaunchers; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.LauncherModularStartupInfo; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.RuntimeLayout; + +final class FromOptions { + + static ApplicationBuilderBuilder buildApplicationBuilder() { + return new ApplicationBuilderBuilder(); + } + + static PackageBuilder createPackageBuilder(Options options, Application app, PackageType type) { + + final var builder = new PackageBuilder(app, type); + + NAME.ifPresentIn(options, builder::name); + DESCRIPTION.ifPresentIn(options, builder::description); + APP_VERSION.ifPresentIn(options, builder::version); + ABOUT_URL.ifPresentIn(options, builder::aboutURL); + LICENSE_FILE.ifPresentIn(options, builder::licenseFile); + PREDEFINED_APP_IMAGE.ifPresentIn(options, builder::predefinedAppImage); + PREDEFINED_RUNTIME_IMAGE.ifPresentIn(options, builder::predefinedAppImage); + INSTALL_DIR.ifPresentIn(options, builder::installDir); + + return builder; + } + + + static final class ApplicationBuilderBuilder { + + private ApplicationBuilderBuilder() { + } + + ApplicationBuilder create(Options options, + Function launcherCtor, + BiFunction launcherOverrideCtor, + ApplicationLayout appLayout) { + + final Optional thePredefinedRuntimeLayout; + if (PREDEFINED_RUNTIME_IMAGE.containsIn(options)) { + thePredefinedRuntimeLayout = Optional.ofNullable( + predefinedRuntimeLayout).or(() -> Optional.of(RuntimeLayout.DEFAULT)); + } else { + thePredefinedRuntimeLayout = Optional.empty(); + } + + final var transfomer = new OptionsTransformer(options, appLayout); + final var appBuilder = createApplicationBuilder( + transfomer.appOptions(), + launcherCtor, + launcherOverrideCtor, + appLayout, + Optional.ofNullable(runtimeLayout).orElse(RuntimeLayout.DEFAULT), + thePredefinedRuntimeLayout); + + transfomer.externalApp().ifPresent(appBuilder::externalApplication); + + return appBuilder; + } + + /** + * Sets the layout of the predefined runtime image. + * @param v the layout of the predefined runtime image. Null is permitted. + * @return this + */ + ApplicationBuilderBuilder predefinedRuntimeLayout(RuntimeLayout v) { + predefinedRuntimeLayout = v; + return this; + } + + /** + * Sets the layout of a runtime bundle. + * @param v the layout of a runtime bundle. Null is permitted. + * @return this + */ + ApplicationBuilderBuilder runtimeLayout(RuntimeLayout v) { + runtimeLayout = v; + return this; + } + + private RuntimeLayout runtimeLayout; + private RuntimeLayout predefinedRuntimeLayout; + } + + + private static ApplicationBuilder createApplicationBuilder(Options options, + Function launcherCtor, + BiFunction launcherOverrideCtor, + ApplicationLayout appLayout, RuntimeLayout runtimeLayout, + Optional predefinedRuntimeLayout) { + + final var appBuilder = new ApplicationBuilder(); + + final var isRuntimeInstaller = isRuntimeInstaller(options); + + final var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.findIn(options); + + final var predefinedRuntimeDirectory = predefinedRuntimeLayout.flatMap(layout -> { + return predefinedRuntimeImage.map(layout::resolveAt); + }).map(RuntimeLayout::runtimeDirectory); + + NAME.findIn(options).or(() -> { + if (isRuntimeInstaller) { + return predefinedRuntimeImage.map(Path::getFileName).map(Path::toString); + } else { + return Optional.empty(); + } + }).ifPresent(appBuilder::name); + DESCRIPTION.ifPresentIn(options, appBuilder::description); + APP_VERSION.ifPresentIn(options, appBuilder::version); + VENDOR.ifPresentIn(options, appBuilder::vendor); + COPYRIGHT.ifPresentIn(options, appBuilder::copyright); + INPUT.ifPresentIn(options, appBuilder::srcDir); + APP_CONTENT.ifPresentIn(options, appBuilder::contentDirs); + + if (isRuntimeInstaller) { + appBuilder.appImageLayout(runtimeLayout); + } else { + appBuilder.appImageLayout(appLayout); + + final var launchers = createLaunchers(options, launcherCtor); + + if (PREDEFINED_APP_IMAGE.containsIn(options)) { + appBuilder.launchers(launchers); + } else { + appBuilder.launchers(normalizeIcons(launchers, RESOURCE_DIR.findIn(options), launcherOverrideCtor)); + + final var runtimeBuilderBuilder = new RuntimeBuilderBuilder(); + + runtimeBuilderBuilder.modulePath(ensureBaseModuleInModulePath(MODULE_PATH.findIn(options).orElseGet(List::of))); + + if (!APP_VERSION.containsIn(options)) { + // Version is not specified explicitly. Try to get it from the app's module. + launchers.mainLauncher().startupInfo().ifPresent(startupInfo -> { + if (startupInfo instanceof LauncherModularStartupInfo modularStartupInfo) { + modularStartupInfo.moduleVersion().ifPresent(moduleVersion -> { + appBuilder.version(moduleVersion); + Log.verbose(I18N.format("message.module-version", + moduleVersion, modularStartupInfo.moduleName())); + }); + } + }); + } + + predefinedRuntimeDirectory.ifPresentOrElse(runtimeBuilderBuilder::forRuntime, () -> { + final var startupInfos = launchers.asList().stream() + .map(Launcher::startupInfo) + .map(Optional::orElseThrow).toList(); + final var jlinkOptionsBuilder = runtimeBuilderBuilder.forNewRuntime(startupInfos); + ADD_MODULES.findIn(options).map(Set::copyOf).ifPresent(jlinkOptionsBuilder::addModules); + JLINK_OPTIONS.ifPresentIn(options, jlinkOptionsBuilder::options); + jlinkOptionsBuilder.apply(); + }); + + appBuilder.runtimeBuilder(runtimeBuilderBuilder.create()); + } + } + + return appBuilder; + } + + private static ApplicationLaunchers createLaunchers(Options options, Function launcherCtor) { + var launchers = ADDITIONAL_LAUNCHERS.getFrom(options); + + var mainLauncher = launcherCtor.apply(options); + + // + // Additional launcher should: + // - Use description from the main launcher by default. + // + var mainLauncherDefaults = Options.of(Map.of(DESCRIPTION, mainLauncher.description())); + + var additionalLaunchers = launchers.stream().map(launcherOptions -> { + return launcherOptions.copyWithParent(mainLauncherDefaults); + }).map(launcherCtor).toList(); + + return new ApplicationLaunchers(mainLauncher, additionalLaunchers); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java deleted file mode 100644 index cee7492dbc7..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.jpackage.internal; - -import static jdk.jpackage.internal.Arguments.CLIOptions.LINUX_SHORTCUT_HINT; -import static jdk.jpackage.internal.Arguments.CLIOptions.WIN_MENU_HINT; -import static jdk.jpackage.internal.Arguments.CLIOptions.WIN_SHORTCUT_HINT; -import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; -import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; -import static jdk.jpackage.internal.StandardBundlerParam.ADD_MODULES; -import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; -import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.JLINK_OPTIONS; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; -import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; -import static jdk.jpackage.internal.StandardBundlerParam.LIMIT_MODULES; -import static jdk.jpackage.internal.StandardBundlerParam.MODULE_PATH; -import static jdk.jpackage.internal.StandardBundlerParam.NAME; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; -import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; -import static jdk.jpackage.internal.StandardBundlerParam.VERSION; -import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; -import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.BiFunction; -import java.util.function.Function; -import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ApplicationLaunchers; -import jdk.jpackage.internal.model.ApplicationLayout; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.ExternalApplication; -import jdk.jpackage.internal.model.ExternalApplication.LauncherInfo; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.LauncherShortcut; -import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; -import jdk.jpackage.internal.model.PackageType; -import jdk.jpackage.internal.model.ParseUtils; -import jdk.jpackage.internal.model.RuntimeLayout; -import jdk.jpackage.internal.util.function.ThrowingFunction; - -final class FromParams { - - static ApplicationBuilder createApplicationBuilder(Map params, - Function, Launcher> launcherMapper, - BiFunction launcherOverrideCtor, - ApplicationLayout appLayout) throws ConfigException, IOException { - return createApplicationBuilder(params, launcherMapper, launcherOverrideCtor, appLayout, RuntimeLayout.DEFAULT, Optional.of(RuntimeLayout.DEFAULT)); - } - - static ApplicationBuilder createApplicationBuilder(Map params, - Function, Launcher> launcherMapper, - BiFunction launcherOverrideCtor, - ApplicationLayout appLayout, RuntimeLayout runtimeLayout, - Optional predefinedRuntimeLayout) throws ConfigException, IOException { - - final var appBuilder = new ApplicationBuilder(); - - APP_NAME.copyInto(params, appBuilder::name); - DESCRIPTION.copyInto(params, appBuilder::description); - appBuilder.version(VERSION.fetchFrom(params)); - VENDOR.copyInto(params, appBuilder::vendor); - COPYRIGHT.copyInto(params, appBuilder::copyright); - SOURCE_DIR.copyInto(params, appBuilder::srcDir); - APP_CONTENT.copyInto(params, appBuilder::contentDirs); - - final var isRuntimeInstaller = isRuntimeInstaller(params); - - final var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.findIn(params); - - final var predefinedRuntimeDirectory = predefinedRuntimeLayout.flatMap( - layout -> predefinedRuntimeImage.map(layout::resolveAt)).map(RuntimeLayout::runtimeDirectory); - - if (isRuntimeInstaller) { - appBuilder.appImageLayout(runtimeLayout); - } else { - appBuilder.appImageLayout(appLayout); - - if (hasPredefinedAppImage(params)) { - final var appImageFile = PREDEFINED_APP_IMAGE_FILE.fetchFrom(params); - appBuilder.initFromExternalApplication(appImageFile, launcherInfo -> { - var launcherParams = mapLauncherInfo(appImageFile, launcherInfo); - return launcherMapper.apply(mergeParams(params, launcherParams)); - }); - } else { - final var launchers = createLaunchers(params, launcherMapper); - - final var runtimeBuilderBuilder = new RuntimeBuilderBuilder(); - - runtimeBuilderBuilder.modulePath(MODULE_PATH.fetchFrom(params)); - - predefinedRuntimeDirectory.ifPresentOrElse(runtimeBuilderBuilder::forRuntime, () -> { - final var startupInfos = launchers.asList().stream() - .map(Launcher::startupInfo) - .map(Optional::orElseThrow).toList(); - final var jlinkOptionsBuilder = runtimeBuilderBuilder.forNewRuntime(startupInfos); - ADD_MODULES.copyInto(params, jlinkOptionsBuilder::addModules); - LIMIT_MODULES.copyInto(params, jlinkOptionsBuilder::limitModules); - JLINK_OPTIONS.copyInto(params, jlinkOptionsBuilder::options); - jlinkOptionsBuilder.apply(); - }); - - final var normalizedLaunchers = ApplicationBuilder.normalizeIcons(launchers, RESOURCE_DIR.findIn(params), launcherOverrideCtor); - - appBuilder.launchers(normalizedLaunchers).runtimeBuilder(runtimeBuilderBuilder.create()); - } - } - - return appBuilder; - } - - static PackageBuilder createPackageBuilder( - Map params, Application app, - PackageType type) throws ConfigException { - - final var builder = new PackageBuilder(app, type); - - builder.name(INSTALLER_NAME.fetchFrom(params)); - DESCRIPTION.copyInto(params, builder::description); - VERSION.copyInto(params, builder::version); - ABOUT_URL.copyInto(params, builder::aboutURL); - LICENSE_FILE.findIn(params).map(Path::of).ifPresent(builder::licenseFile); - PREDEFINED_APP_IMAGE.findIn(params).ifPresent(builder::predefinedAppImage); - PREDEFINED_RUNTIME_IMAGE.findIn(params).ifPresent(builder::predefinedAppImage); - INSTALL_DIR.findIn(params).map(Path::of).ifPresent(builder::installDir); - - return builder; - } - - static BundlerParamInfo createApplicationBundlerParam( - ThrowingFunction, T> ctor) { - return BundlerParamInfo.createBundlerParam(Application.class, ctor); - } - - static BundlerParamInfo createPackageBundlerParam( - ThrowingFunction, T> ctor) { - return BundlerParamInfo.createBundlerParam(jdk.jpackage.internal.model.Package.class, ctor); - } - - static Optional getCurrentPackage(Map params) { - return Optional.ofNullable((jdk.jpackage.internal.model.Package)params.get( - jdk.jpackage.internal.model.Package.class.getName())); - } - - static Optional findLauncherShortcut( - BundlerParamInfo shortcutParam, - Map mainParams, - Map launcherParams) { - - Optional launcherValue; - if (launcherParams == mainParams) { - // The main launcher - launcherValue = Optional.empty(); - } else { - launcherValue = shortcutParam.findIn(launcherParams); - } - - return launcherValue.map(ParseUtils::parseLauncherShortcutForAddLauncher).or(() -> { - return Optional.ofNullable(mainParams.get(shortcutParam.getID())).map(toFunction(value -> { - if (value instanceof Boolean) { - return new LauncherShortcut(LauncherShortcutStartupDirectory.DEFAULT); - } else { - try { - return ParseUtils.parseLauncherShortcutForMainLauncher((String)value); - } catch (IllegalArgumentException ex) { - throw I18N.buildConfigException("error.invalid-option-value", value, "--" + shortcutParam.getID()).create(); - } - } - })); - }); - } - - private static ApplicationLaunchers createLaunchers( - Map params, - Function, Launcher> launcherMapper) { - var launchers = ADD_LAUNCHERS.findIn(params).orElseGet(List::of); - - var mainLauncher = launcherMapper.apply(params); - var additionalLaunchers = launchers.stream().map(launcherParams -> { - return launcherMapper.apply(mergeParams(params, launcherParams)); - }).toList(); - - return new ApplicationLaunchers(mainLauncher, additionalLaunchers); - } - - private static Map mapLauncherInfo(ExternalApplication appImageFile, LauncherInfo launcherInfo) { - Map launcherParams = new HashMap<>(); - launcherParams.put(NAME.getID(), launcherInfo.name()); - if (!appImageFile.getLauncherName().equals(launcherInfo.name())) { - // This is not the main launcher, accept the value - // of "launcher-as-service" from the app image file (.jpackage.xml). - launcherParams.put(LAUNCHER_AS_SERVICE.getID(), Boolean.toString(launcherInfo.service())); - } - launcherParams.putAll(launcherInfo.extra()); - return launcherParams; - } - - private static Map mergeParams(Map mainParams, - Map launcherParams) { - if (!launcherParams.containsKey(DESCRIPTION.getID())) { - launcherParams = new HashMap<>(launcherParams); -// FIXME: this is a good improvement but it fails existing tests -// launcherParams.put(DESCRIPTION.getID(), String.format("%s (%s)", DESCRIPTION.fetchFrom( -// mainParams), APP_NAME.fetchFrom(launcherParams))); - launcherParams.put(DESCRIPTION.getID(), DESCRIPTION.fetchFrom(mainParams)); - } - return AddLauncherArguments.merge(mainParams, launcherParams, ICON.getID(), - ADD_LAUNCHERS.getID(), FILE_ASSOCIATIONS.getID(), WIN_MENU_HINT.getId(), - WIN_SHORTCUT_HINT.getId(), LINUX_SHORTCUT_HINT.getId()); - } - - static final BundlerParamInfo APPLICATION = createApplicationBundlerParam(null); -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java index 427051719bb..aac113d7777 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java @@ -32,7 +32,7 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.List; -import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.JPackageException; /** * IOUtils @@ -90,19 +90,17 @@ final class IOUtils { } } - static void writableOutputDir(Path outdir) throws PackagerException { + static void writableOutputDir(Path outdir) { if (!Files.isDirectory(outdir)) { try { Files.createDirectories(outdir); } catch (IOException ex) { - throw new PackagerException("error.cannot-create-output-dir", - outdir.toAbsolutePath().toString()); + throw new JPackageException(I18N.format("error.cannot-create-output-dir", outdir.toAbsolutePath())); } } if (!Files.isWritable(outdir)) { - throw new PackagerException("error.cannot-write-to-output-dir", - outdir.toAbsolutePath().toString()); + throw new JPackageException(I18N.format("error.cannot-write-to-output-dir", outdir.toAbsolutePath())); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java index 2273d385936..37f166a4e7c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java @@ -36,7 +36,6 @@ import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; import java.nio.file.Files; import java.nio.file.Path; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -51,10 +50,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.module.ModulePath; import jdk.jpackage.internal.model.AppImageLayout; -import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.LauncherModularStartupInfo; import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.RuntimeBuilder; final class JLinkRuntimeBuilder implements RuntimeBuilder { @@ -64,7 +62,7 @@ final class JLinkRuntimeBuilder implements RuntimeBuilder { } @Override - public void create(AppImageLayout appImageLayout) throws PackagerException { + public void create(AppImageLayout appImageLayout) { var args = new ArrayList(); args.add("--output"); args.add(appImageLayout.runtimeDirectory().toString()); @@ -79,10 +77,15 @@ final class JLinkRuntimeBuilder implements RuntimeBuilder { args.add(0, "jlink"); Log.verbose(args, List.of(jlinkOut), retVal, -1); if (retVal != 0) { - throw new PackagerException("error.jlink.failed", jlinkOut); + throw new JPackageException(I18N.format("error.jlink.failed", jlinkOut)); } } + @Override + public boolean withNativeCommands() { + return !jlinkCmdLine.contains("--strip-native-commands"); + } + static ModuleFinder createModuleFinder(Collection modulePath) { return ModuleFinder.compose( ModulePath.of(JarFile.runtimeVersion(), true, @@ -91,7 +94,7 @@ final class JLinkRuntimeBuilder implements RuntimeBuilder { } static RuntimeBuilder createJLinkRuntimeBuilder(List modulePath, Set addModules, - Set limitModules, List options, List startupInfos) throws ConfigException { + Set limitModules, List options, List startupInfos) { return new JLinkRuntimeBuilder(createJLinkCmdline(modulePath, addModules, limitModules, options, startupInfos)); } @@ -143,7 +146,7 @@ final class JLinkRuntimeBuilder implements RuntimeBuilder { } private static List createJLinkCmdline(List modulePath, Set addModules, - Set limitModules, List options, List startupInfos) throws ConfigException { + Set limitModules, List options, List startupInfos) { List launcherModules = startupInfos.stream().map(si -> { if (si instanceof LauncherModularStartupInfo siModular) { return siModular.moduleName(); @@ -177,8 +180,7 @@ final class JLinkRuntimeBuilder implements RuntimeBuilder { for (String option : options) { switch (option) { case "--output", "--add-modules", "--module-path" -> { - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.blocked.option"), option), null); + throw I18N.buildConfigException("error.blocked.option", option).create(); } default -> { args.add(option); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JPackageToolProvider.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JPackageToolProvider.java deleted file mode 100644 index 079d03a076c..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JPackageToolProvider.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2017, 2022, 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 jdk.jpackage.internal; - -import java.io.PrintWriter; -import java.util.Optional; -import java.util.spi.ToolProvider; - -/** - * JPackageToolProvider - * - * This is the ToolProvider implementation exported - * to java.util.spi.ToolProvider and ultimately javax.tools.ToolProvider - */ -public class JPackageToolProvider implements ToolProvider { - - public String name() { - return "jpackage"; - } - - public Optional description() { - return Optional.of(jdk.jpackage.main.Main.I18N.getString("jpackage.description")); - } - - public synchronized int run( - PrintWriter out, PrintWriter err, String... args) { - try { - return new jdk.jpackage.main.Main().execute(out, err, args); - } catch (RuntimeException re) { - Log.fatalError(re.getMessage()); - Log.verbose(re); - return 1; - } - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java index 0f6b5d6ac8d..e3720e0a776 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherBuilder.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; import static jdk.jpackage.internal.I18N.buildConfigException; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import java.nio.file.Path; import java.util.List; @@ -34,23 +33,20 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Function; import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.CustomLauncherIcon; -import jdk.jpackage.internal.model.DefaultLauncherIcon; import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.Launcher.Stub; -import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.model.LauncherIcon; import jdk.jpackage.internal.model.LauncherStartupInfo; -import jdk.jpackage.internal.model.ResourceDirLauncherIcon; +import jdk.jpackage.internal.util.PathUtils; final class LauncherBuilder { - Launcher create() throws ConfigException { + Launcher create() { CustomLauncherIcon.fromLauncherIcon(icon) .map(CustomLauncherIcon::path) - .ifPresent(toConsumer(LauncherBuilder::validateIcon)); + .ifPresent(LauncherBuilder::validateIcon); final var fa = createFileAssociations(faSources, Optional.ofNullable(faTraits).orElse(DEFAULT_FA_TRAITS)); @@ -123,7 +119,7 @@ final class LauncherBuilder { .setCategory("icon"); } - static void validateIcon(Path icon) throws ConfigException { + static Path validateIcon(Path icon) { switch (OperatingSystem.current()) { case WINDOWS -> { if (!icon.getFileName().toString().toLowerCase().endsWith(".ico")) { @@ -144,13 +140,15 @@ final class LauncherBuilder { throw new UnsupportedOperationException(); } } + + return icon; } record FileAssociationTraits() { } private static List createFileAssociations( - List groups, FileAssociationTraits faTraits) throws ConfigException { + List groups, FileAssociationTraits faTraits) { Objects.requireNonNull(groups); Objects.requireNonNull(faTraits); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java deleted file mode 100644 index 488e9106479..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (c) 2020, 2025, 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 jdk.jpackage.internal; - -import jdk.jpackage.internal.model.ConfigException; -import java.io.File; -import java.io.IOException; -import java.lang.module.ModuleReference; -import java.nio.file.Files; -import java.nio.file.InvalidPathException; -import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Supplier; -import java.util.jar.Attributes; -import java.util.jar.JarFile; -import java.util.jar.Manifest; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; - -/** - * Extracts data needed to run application from parameters. - */ -final class LauncherData { - boolean isModular() { - return moduleInfo != null; - } - - String qualifiedClassName() { - return qualifiedClassName; - } - - boolean isClassNameFromMainJar() { - return jarMainClass != null; - } - - String packageName() { - int sepIdx = qualifiedClassName.lastIndexOf('.'); - if (sepIdx < 0) { - return ""; - } - return qualifiedClassName.substring(sepIdx + 1); - } - - String moduleName() { - verifyIsModular(true); - return moduleInfo.name(); - } - - List modulePath() { - verifyIsModular(true); - return modulePath; - } - - Path mainJarName() { - verifyIsModular(false); - return mainJarName; - } - - List classPath() { - return classPath; - } - - String getAppVersion() { - if (isModular()) { - return moduleInfo.version().orElse(null); - } - - return null; - } - - private LauncherData() { - } - - private void verifyIsModular(boolean isModular) { - if ((moduleInfo == null) == isModular) { - throw new IllegalStateException(); - } - } - - static LauncherData create(Map params) throws - ConfigException, IOException { - - final String mainModule = getMainModule(params); - final LauncherData result; - if (mainModule == null) { - result = createNonModular(params); - } else { - result = createModular(mainModule, params); - } - result.initClasspath(params); - return result; - } - - private static LauncherData createModular(String mainModule, - Map params) throws ConfigException, - IOException { - - LauncherData launcherData = new LauncherData(); - - final int sepIdx = mainModule.indexOf("/"); - final String moduleName; - if (sepIdx > 0) { - launcherData.qualifiedClassName = mainModule.substring(sepIdx + 1); - moduleName = mainModule.substring(0, sepIdx); - } else { - moduleName = mainModule; - } - launcherData.modulePath = getModulePath(params); - - // Try to find module in the specified module path list. - ModuleReference moduleRef = JLinkRuntimeBuilder.createModuleFinder( - launcherData.modulePath).find(moduleName).orElse(null); - - if (moduleRef != null) { - launcherData.moduleInfo = ModuleInfo.fromModuleReference(moduleRef); - } else if (params.containsKey(PREDEFINED_RUNTIME_IMAGE.getID())) { - // Failed to find module in the specified module path list and - // there is external runtime given to jpackage. - // Lookup module in this runtime. - Path cookedRuntime = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); - launcherData.moduleInfo = ModuleInfo.fromCookedRuntime(moduleName, - cookedRuntime).orElse(null); - } - - if (launcherData.moduleInfo == null) { - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.no-module-in-path"), moduleName), null); - } - - if (launcherData.qualifiedClassName == null) { - launcherData.qualifiedClassName = launcherData.moduleInfo.mainClass().orElse(null); - if (launcherData.qualifiedClassName == null) { - throw new ConfigException(I18N.getString("ERR_NoMainClass"), null); - } - } - - return launcherData; - } - - private static LauncherData createNonModular( - Map params) throws ConfigException, IOException { - LauncherData launcherData = new LauncherData(); - - launcherData.qualifiedClassName = getMainClass(params); - - launcherData.mainJarName = getMainJarName(params); - - Path mainJarDir = StandardBundlerParam.SOURCE_DIR.fetchFrom(params); - - final Path mainJarPath; - if (launcherData.mainJarName != null && mainJarDir != null) { - mainJarPath = mainJarDir.resolve(launcherData.mainJarName); - if (!Files.exists(mainJarPath)) { - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.main-jar-does-not-exist"), - launcherData.mainJarName), I18N.getString( - "error.main-jar-does-not-exist.advice")); - } - } else { - mainJarPath = null; - } - - if (launcherData.qualifiedClassName == null) { - if (mainJarPath == null) { - throw new ConfigException(I18N.getString("error.no-main-class"), - I18N.getString("error.no-main-class.advice")); - } - - try (JarFile jf = new JarFile(mainJarPath.toFile())) { - Manifest m = jf.getManifest(); - Attributes attrs = (m != null) ? m.getMainAttributes() : null; - if (attrs != null) { - launcherData.qualifiedClassName = attrs.getValue( - Attributes.Name.MAIN_CLASS); - launcherData.jarMainClass = launcherData.qualifiedClassName; - } - } - } - - if (launcherData.qualifiedClassName == null) { - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.no-main-class-with-main-jar"), - launcherData.mainJarName), MessageFormat.format( - I18N.getString( - "error.no-main-class-with-main-jar.advice"), - launcherData.mainJarName)); - } - - return launcherData; - } - - private void initClasspath(Map params) - throws IOException { - Path inputDir = StandardBundlerParam.SOURCE_DIR.fetchFrom(params); - if (inputDir == null) { - classPath = Collections.emptyList(); - } else { - try (Stream walk = Files.walk(inputDir, Integer.MAX_VALUE)) { - Set jars = walk.filter(Files::isRegularFile) - .filter(file -> file.toString().endsWith(".jar")) - .map(p -> inputDir.toAbsolutePath() - .relativize(p.toAbsolutePath())) - .collect(Collectors.toSet()); - jars.remove(mainJarName); - classPath = jars.stream().sorted().toList(); - } - } - } - - private static String getMainClass(Map params) { - return getStringParam(params, Arguments.CLIOptions.APPCLASS.getId()); - } - - private static Path getMainJarName(Map params) - throws ConfigException { - return getPathParam(params, Arguments.CLIOptions.MAIN_JAR.getId()); - } - - private static String getMainModule(Map params) { - return getStringParam(params, Arguments.CLIOptions.MODULE.getId()); - } - - private static String getStringParam(Map params, - String paramName) { - Optional value = Optional.ofNullable(params.get(paramName)); - return value.map(Object::toString).orElse(null); - } - - private static T getPathParam(String paramName, Supplier func) throws ConfigException { - try { - return func.get(); - } catch (InvalidPathException ex) { - throw new ConfigException(MessageFormat.format(I18N.getString( - "error.not-path-parameter"), paramName, - ex.getLocalizedMessage()), null, ex); - } - } - - private static Path getPathParam(Map params, - String paramName) throws ConfigException { - return getPathParam(paramName, () -> { - String value = getStringParam(params, paramName); - Path result = null; - if (value != null) { - result = Path.of(value); - } - return result; - }); - } - - private static List getModulePath(Map params) - throws ConfigException { - List modulePath = getPathListParameter(Arguments.CLIOptions.MODULE_PATH.getId(), params); - - if (params.containsKey(PREDEFINED_RUNTIME_IMAGE.getID())) { - Path runtimePath = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); - runtimePath = runtimePath.resolve("lib"); - modulePath = Stream.of(modulePath, List.of(runtimePath)) - .flatMap(List::stream) - .toList(); - } - - return modulePath; - } - - private static List getPathListParameter(String paramName, - Map params) throws ConfigException { - return getPathParam(paramName, () -> - params.get(paramName) instanceof String value ? - Stream.of(value.split(File.pathSeparator)).map(Path::of).toList() : List.of()); - } - - private String qualifiedClassName; - private String jarMainClass; - private Path mainJarName; - private List classPath; - private List modulePath; - private ModuleInfo moduleInfo; -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java new file mode 100644 index 00000000000..0749cc48b9b --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal; + +import static jdk.jpackage.internal.cli.StandardOption.APPCLASS; +import static jdk.jpackage.internal.cli.StandardOption.ARGUMENTS; +import static jdk.jpackage.internal.cli.StandardOption.DESCRIPTION; +import static jdk.jpackage.internal.cli.StandardOption.FILE_ASSOCIATIONS; +import static jdk.jpackage.internal.cli.StandardOption.ICON; +import static jdk.jpackage.internal.cli.StandardOption.INPUT; +import static jdk.jpackage.internal.cli.StandardOption.JAVA_OPTIONS; +import static jdk.jpackage.internal.cli.StandardOption.LAUNCHER_AS_SERVICE; +import static jdk.jpackage.internal.cli.StandardOption.MAIN_JAR; +import static jdk.jpackage.internal.cli.StandardOption.MODULE; +import static jdk.jpackage.internal.cli.StandardOption.MODULE_PATH; +import static jdk.jpackage.internal.cli.StandardOption.NAME; +import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_RUNTIME_IMAGE; + +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.stream.IntStream; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.FileAssociationGroup.FileAssociationException; +import jdk.jpackage.internal.FileAssociationGroup.FileAssociationNoExtensionsException; +import jdk.jpackage.internal.FileAssociationGroup.FileAssociationNoMimesException; +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.cli.StandardFaOption; +import jdk.jpackage.internal.model.CustomLauncherIcon; +import jdk.jpackage.internal.model.DefaultLauncherIcon; +import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.LauncherIcon; + +final class LauncherFromOptions { + + LauncherFromOptions() { + } + + LauncherFromOptions faGroupBuilderMutator(BiConsumer v) { + faGroupBuilderMutator = v; + return this; + } + + LauncherFromOptions faMapper(BiFunction v) { + faMapper = v; + return this; + } + + LauncherFromOptions faWithDefaultDescription() { + return faGroupBuilderMutator((faGroupBuilder, launcherBuilder) -> { + if (faGroupBuilder.description().isEmpty()) { + var description = String.format("%s association", launcherBuilder.create().name()); + faGroupBuilder.description(description); + } + }); + } + + Launcher create(Options options) { + final var builder = new LauncherBuilder().defaultIconResourceName(defaultIconResourceName()); + + DESCRIPTION.ifPresentIn(options, builder::description); + builder.icon(toLauncherIcon(ICON.findIn(options).orElse(null))); + LAUNCHER_AS_SERVICE.ifPresentIn(options, builder::isService); + NAME.ifPresentIn(options, builder::name); + + if (PREDEFINED_APP_IMAGE.findIn(options).isEmpty()) { + final var startupInfoBuilder = new LauncherStartupInfoBuilder(); + + INPUT.ifPresentIn(options, startupInfoBuilder::inputDir); + ARGUMENTS.ifPresentIn(options, startupInfoBuilder::defaultParameters); + JAVA_OPTIONS.ifPresentIn(options, startupInfoBuilder::javaOptions); + MAIN_JAR.ifPresentIn(options, startupInfoBuilder::mainJar); + APPCLASS.ifPresentIn(options, startupInfoBuilder::mainClassName); + MODULE.ifPresentIn(options, startupInfoBuilder::moduleName); + MODULE_PATH.ifPresentIn(options, startupInfoBuilder::modulePath); + PREDEFINED_RUNTIME_IMAGE.ifPresentIn(options, startupInfoBuilder::predefinedRuntimeImage); + + builder.startupInfo(startupInfoBuilder.create()); + } + + final var faOptionsList = FILE_ASSOCIATIONS.findIn(options).orElseGet(List::of); + + final var faGroups = IntStream.range(0, faOptionsList.size()).mapToObj(idx -> { + final var faOptions = faOptionsList.get(idx); + + final var faGroupBuilder = FileAssociationGroup.build(); + + StandardFaOption.DESCRIPTION.ifPresentIn(faOptions, faGroupBuilder::description); + StandardFaOption.ICON.ifPresentIn(faOptions, faGroupBuilder::icon); + StandardFaOption.EXTENSIONS.ifPresentIn(faOptions, faGroupBuilder::extensions); + StandardFaOption.CONTENT_TYPE.ifPresentIn(faOptions, faGroupBuilder::mimeTypes); + + faGroupBuilderMutator().ifPresent(mutator -> { + mutator.accept(faGroupBuilder, builder); + }); + + final var faID = idx + 1; + + final FileAssociationGroup faGroup; + try { + faGroup = faGroupBuilder.create(); + } catch (FileAssociationNoMimesException ex) { + throw I18N.buildConfigException() + .message("error.no-content-types-for-file-association", faID) + .advice("error.no-content-types-for-file-association.advice", faID) + .create(); + } catch (FileAssociationNoExtensionsException ex) { + // TODO: Must do something about this condition! + throw new AssertionError(); + } catch (FileAssociationException ex) { + // Should never happen + throw new UnsupportedOperationException(ex); + } + + return faMapper().map(mapper -> { + return new FileAssociationGroup(faGroup.items().stream().map(fa -> { + return mapper.apply(faOptions, fa); + }).toList()); + }).orElse(faGroup); + + }).toList(); + + return builder.faGroups(faGroups).create(); + } + + private Optional> faGroupBuilderMutator() { + return Optional.ofNullable(faGroupBuilderMutator); + } + + private Optional> faMapper() { + return Optional.ofNullable(faMapper); + } + + private static LauncherIcon toLauncherIcon(Path launcherIconPath) { + if (launcherIconPath == null) { + return DefaultLauncherIcon.INSTANCE; + } else if (launcherIconPath.toString().isEmpty()) { + return null; + } else { + return CustomLauncherIcon.create(launcherIconPath); + } + } + + private static String defaultIconResourceName() { + switch (OperatingSystem.current()) { + case WINDOWS -> { + return "JavaApp.ico"; + } + case LINUX -> { + return "JavaApp.png"; + } + case MACOS -> { + return "JavaApp.icns"; + } + default -> { + throw new UnsupportedOperationException(); + } + } + } + + private BiConsumer faGroupBuilderMutator; + private BiFunction faMapper; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java deleted file mode 100644 index b4ce1cdb200..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromParams.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2025, 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 jdk.jpackage.internal; - -import static jdk.jpackage.internal.I18N.buildConfigException; -import static jdk.jpackage.internal.StandardBundlerParam.ARGUMENTS; -import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.FA_CONTENT_TYPE; -import static jdk.jpackage.internal.StandardBundlerParam.FA_DESCRIPTION; -import static jdk.jpackage.internal.StandardBundlerParam.FA_EXTENSIONS; -import static jdk.jpackage.internal.StandardBundlerParam.FA_ICON; -import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import static jdk.jpackage.internal.StandardBundlerParam.JAVA_OPTIONS; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; -import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA; -import static jdk.jpackage.internal.StandardBundlerParam.NAME; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; - -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.BiFunction; -import java.util.stream.IntStream; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.CustomLauncherIcon; -import jdk.jpackage.internal.model.DefaultLauncherIcon; -import jdk.jpackage.internal.model.FileAssociation; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.LauncherIcon; - -record LauncherFromParams(Optional, FileAssociation>> faExtension) { - - LauncherFromParams { - Objects.requireNonNull(faExtension); - } - - LauncherFromParams() { - this(Optional.empty()); - } - - Launcher create(Map params) throws ConfigException { - final var builder = new LauncherBuilder().defaultIconResourceName(defaultIconResourceName()); - - DESCRIPTION.copyInto(params, builder::description); - builder.icon(toLauncherIcon(ICON.findIn(params).orElse(null))); - LAUNCHER_AS_SERVICE.copyInto(params, builder::isService); - NAME.copyInto(params, builder::name); - - if (PREDEFINED_APP_IMAGE.findIn(params).isEmpty()) { - final var startupInfoBuilder = new LauncherStartupInfoBuilder(); - - startupInfoBuilder.launcherData(LAUNCHER_DATA.fetchFrom(params)); - ARGUMENTS.copyInto(params, startupInfoBuilder::defaultParameters); - JAVA_OPTIONS.copyInto(params, startupInfoBuilder::javaOptions); - - builder.startupInfo(startupInfoBuilder.create()); - } - - final var faParamsList = FILE_ASSOCIATIONS.findIn(params).orElseGet(List::of); - - final var faGroups = IntStream.range(0, faParamsList.size()).mapToObj(idx -> { - final var faParams = faParamsList.get(idx); - return toSupplier(() -> { - final var faGroupBuilder = FileAssociationGroup.build(); - - if (OperatingSystem.current() == OperatingSystem.MACOS) { - FA_DESCRIPTION.copyInto(faParams, faGroupBuilder::description); - } else { - faGroupBuilder.description(FA_DESCRIPTION.findIn(faParams).orElseGet(() -> { - return String.format("%s association", toSupplier(builder::create).get().name()); - })); - } - - FA_ICON.copyInto(faParams, faGroupBuilder::icon); - FA_EXTENSIONS.copyInto(faParams, faGroupBuilder::extensions); - FA_CONTENT_TYPE.copyInto(faParams, faGroupBuilder::mimeTypes); - - final var faID = idx + 1; - - final FileAssociationGroup faGroup; - try { - faGroup = faGroupBuilder.create(); - } catch (FileAssociationGroup.FileAssociationNoMimesException ex) { - throw buildConfigException() - .message("error.no-content-types-for-file-association", faID) - .advice("error.no-content-types-for-file-association.advice", faID) - .create(); - } - - if (faExtension.isPresent()) { - return new FileAssociationGroup(faGroup.items().stream().map(fa -> { - return faExtension.get().apply(fa, faParams); - }).toList()); - } else { - return faGroup; - } - }).get(); - }).toList(); - - return builder.faGroups(faGroups).create(); - } - - private static LauncherIcon toLauncherIcon(Path launcherIconPath) { - if (launcherIconPath == null) { - return DefaultLauncherIcon.INSTANCE; - } else if (launcherIconPath.toString().isEmpty()) { - return null; - } else { - return CustomLauncherIcon.create(launcherIconPath); - } - } - - private static String defaultIconResourceName() { - switch (OperatingSystem.current()) { - case WINDOWS -> { - return "JavaApp.ico"; - } - case LINUX -> { - return "JavaApp.png"; - } - case MACOS -> { - return "JavaApp.icns"; - } - default -> { - throw new UnsupportedOperationException(); - } - } - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java index 5273f2d251c..b2fc48af9e4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java @@ -24,69 +24,216 @@ */ package jdk.jpackage.internal; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.List; -import java.util.function.UnaryOperator; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.stream.Stream; +import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.LauncherJarStartupInfo; import jdk.jpackage.internal.model.LauncherJarStartupInfoMixin; import jdk.jpackage.internal.model.LauncherModularStartupInfo; import jdk.jpackage.internal.model.LauncherModularStartupInfoMixin; -import jdk.jpackage.internal.model.LauncherStartupInfo.Stub; import jdk.jpackage.internal.model.LauncherStartupInfo; final class LauncherStartupInfoBuilder { LauncherStartupInfo create() { - return decorator.apply(new Stub(qualifiedClassName, javaOptions, - defaultParameters, classPath)); + if (moduleName != null) { + return createModular(); + } else if (mainJar != null) { + return createNonModular(); + } else { + throw new JPackageException(I18N.format("ERR_NoEntryPoint")); + } } - LauncherStartupInfoBuilder launcherData(LauncherData launcherData) { - if (launcherData.isModular()) { - decorator = new ModuleStartupInfo(launcherData.moduleName()); - } else { - decorator = new JarStartupInfo(launcherData.mainJarName(), - launcherData.isClassNameFromMainJar()); - } - classPath = launcherData.classPath(); - qualifiedClassName = launcherData.qualifiedClassName(); + LauncherStartupInfoBuilder inputDir(Path v) { + inputDir = v; return this; } LauncherStartupInfoBuilder javaOptions(List v) { + if (v != null) { + v.forEach(Objects::requireNonNull); + } javaOptions = v; return this; } LauncherStartupInfoBuilder defaultParameters(List v) { + if (v != null) { + v.forEach(Objects::requireNonNull); + } defaultParameters = v; return this; } - private static record ModuleStartupInfo(String moduleName) implements UnaryOperator { + LauncherStartupInfoBuilder mainJar(Path v) { + mainJar = v; + return this; + } - @Override - public LauncherStartupInfo apply(LauncherStartupInfo base) { - return LauncherModularStartupInfo.create(base, - new LauncherModularStartupInfoMixin.Stub(moduleName)); + LauncherStartupInfoBuilder mainClassName(String v) { + mainClassName = v; + return this; + } + + LauncherStartupInfoBuilder predefinedRuntimeImage(Path v) { + cookedRuntimePath = v; + return this; + } + + LauncherStartupInfoBuilder moduleName(String v) { + if (v == null) { + moduleName = null; + } else { + var slashIdx = v.indexOf('/'); + if (slashIdx < 0) { + moduleName = v; + } else { + moduleName = v.substring(0, slashIdx); + if (slashIdx < v.length() - 1) { + mainClassName(v.substring(slashIdx + 1)); + } + } + } + return this; + } + + LauncherStartupInfoBuilder modulePath(List v) { + modulePath = v; + return this; + } + + private Optional inputDir() { + return Optional.ofNullable(inputDir); + } + + private Optional mainClassName() { + return Optional.ofNullable(mainClassName); + } + + private Optional cookedRuntimePath() { + return Optional.ofNullable(cookedRuntimePath); + } + + private LauncherStartupInfo createLauncherStartupInfo(String mainClassName, List classpath) { + Objects.requireNonNull(mainClassName); + classpath.forEach(Objects::requireNonNull); + return new LauncherStartupInfo.Stub(mainClassName, + Optional.ofNullable(javaOptions).orElseGet(List::of), + Optional.ofNullable(defaultParameters).orElseGet(List::of), + classpath); + } + + private static List createClasspath(Path inputDir, Set excludes) { + excludes.forEach(Objects::requireNonNull); + try (final var walk = Files.walk(inputDir)) { + return walk.filter(Files::isRegularFile) + .filter(file -> file.getFileName().toString().endsWith(".jar")) + .map(inputDir::relativize) + .filter(Predicate.not(excludes::contains)) + .distinct() + .toList(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); } } - private static record JarStartupInfo(Path jarPath, - boolean isClassNameFromMainJar) implements - UnaryOperator { + private LauncherModularStartupInfo createModular() { + final var fullModulePath = getFullModulePath(); - @Override - public LauncherStartupInfo apply(LauncherStartupInfo base) { - return LauncherJarStartupInfo.create(base, - new LauncherJarStartupInfoMixin.Stub(jarPath, - isClassNameFromMainJar)); - } + // Try to find the module in the specified module path list. + final var moduleInfo = JLinkRuntimeBuilder.createModuleFinder(fullModulePath).find(moduleName) + .map(ModuleInfo::fromModuleReference).or(() -> { + // Failed to find the module in the specified module path list. + return cookedRuntimePath().flatMap(cookedRuntime -> { + // Lookup the module in the external runtime. + return ModuleInfo.fromCookedRuntime(moduleName, cookedRuntime); + }); + }).orElseThrow(() -> { + return I18N.buildConfigException("error.no-module-in-path", moduleName).create(); + }); + + final var effectiveMainClassName = mainClassName().or(moduleInfo::mainClass).orElseThrow(() -> { + return I18N.buildConfigException("ERR_NoMainClass").create(); + }); + + // If module is located in the file system, exclude it from the classpath. + final var classpath = inputDir().map(theInputDir -> { + var classpathExcludes = moduleInfo.fileLocation().filter(moduleFile -> { + return moduleFile.startsWith(theInputDir); + }).map(theInputDir::relativize).map(Set::of).orElseGet(Set::of); + return createClasspath(theInputDir, classpathExcludes); + }).orElseGet(List::of); + + return LauncherModularStartupInfo.create( + createLauncherStartupInfo(effectiveMainClassName, classpath), + new LauncherModularStartupInfoMixin.Stub(moduleInfo.name(), moduleInfo.version())); } - private String qualifiedClassName; + private List getFullModulePath() { + return cookedRuntimePath().map(runtimeImage -> { + return Stream.of(modulePath(), List.of(runtimeImage.resolve("lib"))).flatMap(List::stream).toList(); + }).orElse(modulePath()); + } + + private List modulePath() { + return Optional.ofNullable(modulePath).orElseGet(List::of); + } + + private LauncherJarStartupInfo createNonModular() { + final var theInputDir = inputDir().orElseThrow(); + + final var mainJarPath = theInputDir.resolve(mainJar); + + if (!Files.exists(mainJarPath)) { + throw I18N.buildConfigException() + .message("error.main-jar-does-not-exist", mainJar) + .advice("error.main-jar-does-not-exist.advice") + .create(); + } + + final var effectiveMainClassName = mainClassName().or(() -> { + try (final var jf = new JarFile(mainJarPath.toFile())) { + return Optional.ofNullable(jf.getManifest()).map(Manifest::getMainAttributes).map(attrs -> { + return attrs.getValue(Attributes.Name.MAIN_CLASS); + }); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }).orElseThrow(() -> { + return I18N.buildConfigException() + .message("error.no-main-class-with-main-jar", mainJar) + .advice("error.no-main-class-with-main-jar.advice", mainJar) + .create(); + }); + + return LauncherJarStartupInfo.create( + createLauncherStartupInfo(effectiveMainClassName, createClasspath(theInputDir, Set.of(mainJar))), + new LauncherJarStartupInfoMixin.Stub(mainJar, mainClassName().isEmpty())); + } + + // Modular options + private String moduleName; + private List modulePath; + + // Non-modular options + private Path mainJar; + + // Common options + private Path inputDir; + private String mainClassName; private List javaOptions; private List defaultParameters; - private List classPath; - private UnaryOperator decorator; + private Path cookedRuntimePath; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OptionUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OptionUtils.java new file mode 100644 index 00000000000..97e1274f078 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OptionUtils.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal; + +import static jdk.jpackage.internal.cli.StandardOption.BUNDLING_OPERATION_DESCRIPTOR; +import static jdk.jpackage.internal.cli.StandardOption.DEST; +import static jdk.jpackage.internal.cli.StandardOption.MAIN_JAR; +import static jdk.jpackage.internal.cli.StandardOption.MODULE; +import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_RUNTIME_IMAGE; + +import java.nio.file.Path; +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.cli.StandardBundlingOperation; + +final class OptionUtils { + + static boolean isRuntimeInstaller(Options options) { + return PREDEFINED_RUNTIME_IMAGE.containsIn(options) + && !PREDEFINED_APP_IMAGE.containsIn(options) + && !MAIN_JAR.containsIn(options) + && !MODULE.containsIn(options); + } + + static Path outputDir(Options options) { + return DEST.getFrom(options); + } + + static StandardBundlingOperation bundlingOperation(Options options) { + return StandardBundlingOperation.valueOf(BUNDLING_OPERATION_DESCRIPTOR.getFrom(options)).orElseThrow(); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OptionsTransformer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OptionsTransformer.java new file mode 100644 index 00000000000..a01be089a49 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OptionsTransformer.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal; + +import static jdk.jpackage.internal.cli.StandardOption.ADDITIONAL_LAUNCHERS; +import static jdk.jpackage.internal.cli.StandardOption.APP_VERSION; +import static jdk.jpackage.internal.cli.StandardOption.ICON; +import static jdk.jpackage.internal.cli.StandardOption.NAME; +import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_APP_IMAGE; + +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.cli.WithOptionIdentifier; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ExternalApplication; + +record OptionsTransformer(Options mainOptions, Optional externalApp) { + + OptionsTransformer { + Objects.requireNonNull(mainOptions); + Objects.requireNonNull(externalApp); + } + + OptionsTransformer(Options mainOptions, ApplicationLayout appLayout) { + this(mainOptions, PREDEFINED_APP_IMAGE.findIn(mainOptions).map(appLayout::resolveAt).map(AppImageFile::load)); + } + + Options appOptions() { + return externalApp.map(ea -> { + var overrideOptions = Map.of( + NAME, ea.appName(), + APP_VERSION, ea.appVersion(), + ADDITIONAL_LAUNCHERS, ea.addLaunchers().stream().map(li -> { + return Options.concat(li.extra(), Options.of(Map.of( + NAME, li.name(), + // This should prevent the code building the Launcher instance + // from the Options object from trying to create a startup info object. + PREDEFINED_APP_IMAGE, PREDEFINED_APP_IMAGE.getFrom(mainOptions) + ))); + }).toList() + ); + return Options.concat( + Options.of(overrideOptions), + ea.extra(), + // Remove icon if any from the application/launcher options. + // If the icon is specified in the main options, it for the installer. + mainOptions.copyWithout(ICON.id()) + ); + }).orElse(mainOptions); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index f93cd0eab14..f537a1ea0a2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -31,7 +31,6 @@ import java.util.Objects; import java.util.Optional; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.Package.Stub; import jdk.jpackage.internal.model.PackageType; @@ -44,7 +43,7 @@ final class PackageBuilder { this.type = Objects.requireNonNull(type); } - Package create() throws ConfigException { + Package create() { final var validatedName = validatedName(); Path relativeInstallDir; @@ -208,8 +207,7 @@ final class PackageBuilder { }); } - private static Path mapInstallDir(Path installDir, PackageType pkgType) - throws ConfigException { + private static Path mapInstallDir(Path installDir, PackageType pkgType) { var ex = buildConfigException("error.invalid-install-dir", installDir).create(); if (installDir.getNameCount() == 0) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Packager.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Packager.java index 501fd64bdca..8e47b046eb1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Packager.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Packager.java @@ -29,7 +29,6 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.PackagerException; final class Packager { @@ -69,7 +68,7 @@ final class Packager { return Objects.requireNonNull(env); } - Path execute(PackagingPipeline.Builder pipelineBuilder) throws PackagerException { + Path execute(PackagingPipeline.Builder pipelineBuilder) { Objects.requireNonNull(pkg); Objects.requireNonNull(env); Objects.requireNonNull(outputDir); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index 6f4e0d0d2d8..a2750fee260 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -46,7 +46,6 @@ import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.pipeline.DirectedEdge; import jdk.jpackage.internal.pipeline.FixedDAG; import jdk.jpackage.internal.pipeline.TaskPipelineBuilder; @@ -62,7 +61,7 @@ final class PackagingPipeline { * @param env the build environment * @param app the application */ - void execute(BuildEnv env, Application app) throws PackagerException { + void execute(BuildEnv env, Application app) { execute(contextMapper.apply(createTaskContext(env, app))); } @@ -81,7 +80,7 @@ final class PackagingPipeline { * @param pkg the package * @param outputDir the output directory for the package file */ - void execute(BuildEnv env, Package pkg, Path outputDir) throws PackagerException { + void execute(BuildEnv env, Package pkg, Path outputDir) { execute((StartupParameters)createPackagingTaskContext(env, pkg, outputDir, taskConfig)); } @@ -91,7 +90,7 @@ final class PackagingPipeline { * * @param startupParameters the pipeline startup parameters */ - void execute(StartupParameters startupParameters) throws PackagerException { + void execute(StartupParameters startupParameters) { execute(contextMapper.apply(createTaskContext((PackagingTaskContext)startupParameters))); } @@ -132,7 +131,7 @@ final class PackagingPipeline { } interface TaskContext extends Predicate { - void execute(TaskAction taskAction) throws IOException, PackagerException; + void execute(TaskAction taskAction) throws IOException; } record AppImageBuildEnv(BuildEnv env, T app) { @@ -161,27 +160,27 @@ final class PackagingPipeline { @FunctionalInterface interface ApplicationImageTaskAction extends TaskAction { - void execute(AppImageBuildEnv env) throws IOException, PackagerException; + void execute(AppImageBuildEnv env) throws IOException; } @FunctionalInterface interface AppImageTaskAction extends TaskAction { - void execute(AppImageBuildEnv env) throws IOException, PackagerException; + void execute(AppImageBuildEnv env) throws IOException; } @FunctionalInterface interface CopyAppImageTaskAction extends TaskAction { - void execute(T pkg, AppImageLayout srcAppImage, AppImageLayout dstAppImage) throws IOException, PackagerException; + void execute(T pkg, AppImageLayout srcAppImage, AppImageLayout dstAppImage) throws IOException; } @FunctionalInterface interface PackageTaskAction extends TaskAction { - void execute(PackageBuildEnv env) throws IOException, PackagerException; + void execute(PackageBuildEnv env) throws IOException; } @FunctionalInterface interface NoArgTaskAction extends TaskAction { - void execute() throws IOException, PackagerException; + void execute() throws IOException; } record TaskConfig(Optional action) { @@ -493,7 +492,7 @@ final class PackagingPipeline { return new PackagingTaskContext(BuildEnv.withAppImageLayout(env, dstLayout), pkg, outputDir, srcLayout); } - private void execute(TaskContext context) throws PackagerException { + private void execute(TaskContext context) { final Map> tasks = taskConfig.entrySet().stream().collect(toMap(Map.Entry::getKey, task -> { return createTask(context, task.getKey(), task.getValue()); })); @@ -508,14 +507,8 @@ final class PackagingPipeline { try { builder.create().call(); - } catch (ExceptionBox ex) { - throw new PackagerException(ex.getCause()); - } catch (RuntimeException ex) { - throw ex; - } catch (PackagerException ex) { - throw ex; } catch (Exception ex) { - throw new PackagerException(ex); + throw ExceptionBox.rethrowUnchecked(ex); } } @@ -546,7 +539,7 @@ final class PackagingPipeline { @SuppressWarnings("unchecked") @Override - public void execute(TaskAction taskAction) throws IOException, PackagerException { + public void execute(TaskAction taskAction) throws IOException { if (taskAction instanceof PackageTaskAction) { ((PackageTaskAction)taskAction).execute(pkgBuildEnv()); } else if (taskAction instanceof CopyAppImageTaskAction) { @@ -600,7 +593,7 @@ final class PackagingPipeline { @SuppressWarnings("unchecked") @Override - public void execute(TaskAction taskAction) throws IOException, PackagerException { + public void execute(TaskAction taskAction) throws IOException { if (taskAction instanceof AppImageTaskAction) { final var taskEnv = pkg.map(PackagingTaskContext::appImageBuildEnv).orElseGet(this::appBuildEnv); ((AppImageTaskAction)taskAction).execute(taskEnv); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java index dcaf097b1a3..a7d9bad39b1 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/RuntimeBuilderBuilder.java @@ -25,7 +25,6 @@ package jdk.jpackage.internal; import static jdk.jpackage.internal.model.RuntimeBuilder.getDefaultModulePath; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import java.io.IOException; import java.io.UncheckedIOException; @@ -38,7 +37,6 @@ import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import jdk.jpackage.internal.model.ApplicationLayout; -import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LauncherStartupInfo; import jdk.jpackage.internal.model.RuntimeBuilder; import jdk.jpackage.internal.util.FileUtils; @@ -112,8 +110,7 @@ final class RuntimeBuilderBuilder { ); } - private static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, - Path... modulePath) throws ConfigException { + private static RuntimeBuilder createCopyingRuntimeBuilder(Path runtimeDir, Path... modulePath) { return appImageLayout -> { try { // copy whole runtime, skipping jmods and src.zip @@ -147,10 +144,9 @@ final class RuntimeBuilderBuilder { @Override public RuntimeBuilder get() { - return toSupplier(() -> createCopyingRuntimeBuilder( + return createCopyingRuntimeBuilder( predefinedRuntimeImage, - Optional.ofNullable(thiz.modulePath).orElseGet(List::of).toArray(Path[]::new)) - ).get(); + Optional.ofNullable(thiz.modulePath).orElseGet(List::of).toArray(Path[]::new)); } } @@ -160,13 +156,12 @@ final class RuntimeBuilderBuilder { @Override public RuntimeBuilder get() { - return toSupplier(() -> JLinkRuntimeBuilder.createJLinkRuntimeBuilder( + return JLinkRuntimeBuilder.createJLinkRuntimeBuilder( Optional.ofNullable(thiz.modulePath).orElseGet(List::of), Optional.ofNullable(addModules).orElseGet(Set::of), Optional.ofNullable(limitModules).orElseGet(Set::of), Optional.ofNullable(options).orElseGet(List::of), - startupInfos) - ).get(); + startupInfos); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java deleted file mode 100644 index 2b35a6830f8..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Copyright (c) 2014, 2025, 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 jdk.jpackage.internal; - - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Stream; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.ExternalApplication; -import static jdk.jpackage.internal.ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT; - -/** - * Standard bundler parameters. - * - * Contains static definitions of all of the common bundler parameters. - * (additional platform specific and mode specific bundler parameters - * are defined in each of the specific bundlers) - * - * Also contains static methods that operate on maps of parameters. - */ -final class StandardBundlerParam { - - private static final String DEFAULT_VERSION = "1.0"; - private static final String DEFAULT_RELEASE = "1"; - private static final String[] DEFAULT_JLINK_OPTIONS = { - "--strip-native-commands", - "--strip-debug", - "--no-man-pages", - "--no-header-files"}; - - static final BundlerParamInfo LAUNCHER_DATA = BundlerParamInfo.createBundlerParam( - LauncherData.class, LauncherData::create); - - static final BundlerParamInfo SOURCE_DIR = - new BundlerParamInfo<>( - Arguments.CLIOptions.INPUT.getId(), - Path.class, - p -> null, - (s, p) -> Path.of(s) - ); - - static final BundlerParamInfo OUTPUT_DIR = - new BundlerParamInfo<>( - Arguments.CLIOptions.OUTPUT.getId(), - Path.class, - p -> Path.of("").toAbsolutePath(), - (s, p) -> Path.of(s) - ); - - // note that each bundler is likely to replace this one with - // their own converter - static final BundlerParamInfo MAIN_JAR = - new BundlerParamInfo<>( - Arguments.CLIOptions.MAIN_JAR.getId(), - Path.class, - params -> LAUNCHER_DATA.fetchFrom(params).mainJarName(), - null - ); - - static final BundlerParamInfo PREDEFINED_APP_IMAGE = - new BundlerParamInfo<>( - Arguments.CLIOptions.PREDEFINED_APP_IMAGE.getId(), - Path.class, - params -> null, - (s, p) -> Path.of(s)); - - static final BundlerParamInfo PREDEFINED_APP_IMAGE_FILE = BundlerParamInfo.createBundlerParam( - ExternalApplication.class, params -> { - if (hasPredefinedAppImage(params)) { - var appImage = PREDEFINED_APP_IMAGE.fetchFrom(params); - return AppImageFile.load(appImage, PLATFORM_APPLICATION_LAYOUT); - } else { - return null; - } - }); - - static final BundlerParamInfo MAIN_CLASS = - new BundlerParamInfo<>( - Arguments.CLIOptions.APPCLASS.getId(), - String.class, - params -> { - if (isRuntimeInstaller(params)) { - return null; - } else if (hasPredefinedAppImage(params)) { - PREDEFINED_APP_IMAGE_FILE.fetchFrom(params).getMainClass(); - } - return LAUNCHER_DATA.fetchFrom(params).qualifiedClassName(); - }, - (s, p) -> s - ); - - static final BundlerParamInfo PREDEFINED_RUNTIME_IMAGE = - new BundlerParamInfo<>( - Arguments.CLIOptions.PREDEFINED_RUNTIME_IMAGE.getId(), - Path.class, - params -> null, - (s, p) -> Path.of(s) - ); - - // this is the raw --app-name arg - used in APP_NAME and INSTALLER_NAME - static final BundlerParamInfo NAME = - new BundlerParamInfo<>( - Arguments.CLIOptions.NAME.getId(), - String.class, - params -> null, - (s, p) -> s - ); - - // this is the application name, either from the app-image (if given), - // the name (if given) derived from the main-class, or the runtime image - static final BundlerParamInfo APP_NAME = - new BundlerParamInfo<>( - "application-name", - String.class, - params -> { - String appName = NAME.fetchFrom(params); - if (hasPredefinedAppImage(params)) { - appName = PREDEFINED_APP_IMAGE_FILE.fetchFrom(params).getLauncherName(); - } else if (appName == null) { - String s = MAIN_CLASS.fetchFrom(params); - if (s != null) { - int idx = s.lastIndexOf("."); - appName = (idx < 0) ? s : s.substring(idx+1); - } else if (isRuntimeInstaller(params)) { - Path f = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); - if (f != null) { - appName = f.getFileName().toString(); - } - } - } - return appName; - }, - (s, p) -> s - ); - - static final BundlerParamInfo INSTALLER_NAME = - new BundlerParamInfo<>( - "installer-name", - String.class, - params -> { - String installerName = NAME.fetchFrom(params); - return (installerName != null) ? installerName : - APP_NAME.fetchFrom(params); - }, - (s, p) -> s - ); - - static final BundlerParamInfo ICON = - new BundlerParamInfo<>( - Arguments.CLIOptions.ICON.getId(), - Path.class, - params -> null, - (s, p) -> Path.of(s) - ); - - static final BundlerParamInfo ABOUT_URL = - new BundlerParamInfo<>( - Arguments.CLIOptions.ABOUT_URL.getId(), - String.class, - params -> null, - (s, p) -> s - ); - - static final BundlerParamInfo VENDOR = - new BundlerParamInfo<>( - Arguments.CLIOptions.VENDOR.getId(), - String.class, - params -> I18N.getString("param.vendor.default"), - (s, p) -> s - ); - - static final BundlerParamInfo DESCRIPTION = - new BundlerParamInfo<>( - Arguments.CLIOptions.DESCRIPTION.getId(), - String.class, - params -> params.containsKey(APP_NAME.getID()) - ? APP_NAME.fetchFrom(params) - : I18N.getString("param.description.default"), - (s, p) -> s - ); - - static final BundlerParamInfo COPYRIGHT = - new BundlerParamInfo<>( - Arguments.CLIOptions.COPYRIGHT.getId(), - String.class, - params -> MessageFormat.format(I18N.getString( - "param.copyright.default"), new Date()), - (s, p) -> s - ); - - @SuppressWarnings("unchecked") - static final BundlerParamInfo> ARGUMENTS = - new BundlerParamInfo<>( - Arguments.CLIOptions.ARGUMENTS.getId(), - (Class>) (Object) List.class, - params -> Collections.emptyList(), - (s, p) -> null - ); - - @SuppressWarnings("unchecked") - static final BundlerParamInfo> JAVA_OPTIONS = - new BundlerParamInfo<>( - Arguments.CLIOptions.JAVA_OPTIONS.getId(), - (Class>) (Object) List.class, - params -> Collections.emptyList(), - (s, p) -> Arrays.asList(s.split("\n\n")) - ); - - static final BundlerParamInfo VERSION = - new BundlerParamInfo<>( - Arguments.CLIOptions.VERSION.getId(), - String.class, - StandardBundlerParam::getDefaultAppVersion, - (s, p) -> s - ); - - static final BundlerParamInfo RELEASE = - new BundlerParamInfo<>( - Arguments.CLIOptions.RELEASE.getId(), - String.class, - params -> DEFAULT_RELEASE, - (s, p) -> s - ); - - public static final BundlerParamInfo LICENSE_FILE = - new BundlerParamInfo<>( - Arguments.CLIOptions.LICENSE_FILE.getId(), - String.class, - params -> null, - (s, p) -> s - ); - - static final BundlerParamInfo TEMP_ROOT = - new BundlerParamInfo<>( - Arguments.CLIOptions.TEMP_ROOT.getId(), - Path.class, - params -> { - try { - return Files.createTempDirectory("jdk.jpackage"); - } catch (IOException ioe) { - return null; - } - }, - (s, p) -> Path.of(s) - ); - - public static final BundlerParamInfo CONFIG_ROOT = - new BundlerParamInfo<>( - "configRoot", - Path.class, - params -> { - Path root = TEMP_ROOT.fetchFrom(params).resolve("config"); - try { - Files.createDirectories(root); - } catch (IOException ioe) { - return null; - } - return root; - }, - (s, p) -> null - ); - - static final BundlerParamInfo VERBOSE = - new BundlerParamInfo<>( - Arguments.CLIOptions.VERBOSE.getId(), - Boolean.class, - params -> false, - // valueOf(null) is false, and we actually do want null - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? - true : Boolean.valueOf(s) - ); - - static final BundlerParamInfo RESOURCE_DIR = - new BundlerParamInfo<>( - Arguments.CLIOptions.RESOURCE_DIR.getId(), - Path.class, - params -> null, - (s, p) -> Path.of(s) - ); - - static final BundlerParamInfo INSTALL_DIR = - new BundlerParamInfo<>( - Arguments.CLIOptions.INSTALL_DIR.getId(), - String.class, - params -> null, - (s, p) -> s - ); - - static final BundlerParamInfo LAUNCHER_AS_SERVICE = - new BundlerParamInfo<>( - Arguments.CLIOptions.LAUNCHER_AS_SERVICE.getId(), - Boolean.class, - params -> false, - // valueOf(null) is false, and we actually do want null - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? - true : Boolean.valueOf(s) - ); - - - @SuppressWarnings("unchecked") - static final BundlerParamInfo>> ADD_LAUNCHERS = - new BundlerParamInfo<>( - Arguments.CLIOptions.ADD_LAUNCHER.getId(), - (Class>>) (Object) - List.class, - params -> new ArrayList<>(1), - // valueOf(null) is false, and we actually do want null - (s, p) -> null - ); - - @SuppressWarnings("unchecked") - static final BundlerParamInfo - >> FILE_ASSOCIATIONS = - new BundlerParamInfo<>( - Arguments.CLIOptions.FILE_ASSOCIATIONS.getId(), - (Class>>) (Object) - List.class, - params -> new ArrayList<>(1), - // valueOf(null) is false, and we actually do want null - (s, p) -> null - ); - - @SuppressWarnings("unchecked") - static final BundlerParamInfo> FA_EXTENSIONS = - new BundlerParamInfo<>( - "fileAssociation.extension", - (Class>) (Object) List.class, - params -> null, // null means not matched to an extension - (s, p) -> Arrays.asList(s.split("(,|\\s)+")) - ); - - @SuppressWarnings("unchecked") - static final BundlerParamInfo> FA_CONTENT_TYPE = - new BundlerParamInfo<>( - "fileAssociation.contentType", - (Class>) (Object) List.class, - params -> null, - // null means not matched to a content/mime type - (s, p) -> Arrays.asList(s.split("(,|\\s)+")) - ); - - static final BundlerParamInfo FA_DESCRIPTION = - new BundlerParamInfo<>( - "fileAssociation.description", - String.class, - p -> null, - (s, p) -> s - ); - - static final BundlerParamInfo FA_ICON = - new BundlerParamInfo<>( - "fileAssociation.icon", - Path.class, - ICON::fetchFrom, - (s, p) -> Path.of(s) - ); - - @SuppressWarnings("unchecked") - static final BundlerParamInfo> DMG_CONTENT = - new BundlerParamInfo<>( - Arguments.CLIOptions.DMG_CONTENT.getId(), - (Class>) (Object)List.class, - p -> Collections.emptyList(), - (s, p) -> Stream.of(s.split(",")).map(Path::of).toList() - ); - - @SuppressWarnings("unchecked") - static final BundlerParamInfo> APP_CONTENT = - new BundlerParamInfo<>( - Arguments.CLIOptions.APP_CONTENT.getId(), - (Class>) (Object)List.class, - p->Collections.emptyList(), - (s, p) -> Stream.of(s.split(",")).map(Path::of).toList() - ); - - @SuppressWarnings("unchecked") - static final BundlerParamInfo> MODULE_PATH = - new BundlerParamInfo<>( - Arguments.CLIOptions.MODULE_PATH.getId(), - (Class>) (Object)List.class, - p -> JLinkRuntimeBuilder.ensureBaseModuleInModulePath(List.of()), - (s, p) -> { - List modulePath = Stream.of(s.split(File.pathSeparator)) - .map(Path::of) - .toList(); - return JLinkRuntimeBuilder.ensureBaseModuleInModulePath(modulePath); - }); - - static final BundlerParamInfo MODULE = - new BundlerParamInfo<>( - Arguments.CLIOptions.MODULE.getId(), - String.class, - p -> null, - (s, p) -> { - return String.valueOf(s); - }); - - @SuppressWarnings("unchecked") - static final BundlerParamInfo> ADD_MODULES = - new BundlerParamInfo<>( - Arguments.CLIOptions.ADD_MODULES.getId(), - (Class>) (Object) Set.class, - p -> new LinkedHashSet(), - (s, p) -> new LinkedHashSet<>(Arrays.asList(s.split(","))) - ); - - @SuppressWarnings("unchecked") - static final BundlerParamInfo> JLINK_OPTIONS = - new BundlerParamInfo<>( - Arguments.CLIOptions.JLINK_OPTIONS.getId(), - (Class>) (Object) List.class, - p -> Arrays.asList(DEFAULT_JLINK_OPTIONS), - (s, p) -> null); - - @SuppressWarnings("unchecked") - static final BundlerParamInfo> LIMIT_MODULES = - new BundlerParamInfo<>( - "limit-modules", - (Class>) (Object) Set.class, - p -> new LinkedHashSet(), - (s, p) -> new LinkedHashSet<>(Arrays.asList(s.split(","))) - ); - - static final BundlerParamInfo SIGN_BUNDLE = - new BundlerParamInfo<>( - Arguments.CLIOptions.MAC_SIGN.getId(), - Boolean.class, - params -> false, - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? - null : Boolean.valueOf(s) - ); - - static boolean isRuntimeInstaller(Map params) { - if (params.containsKey(MODULE.getID()) || - params.containsKey(MAIN_JAR.getID()) || - params.containsKey(PREDEFINED_APP_IMAGE.getID())) { - return false; // we are building or are given an application - } - // runtime installer requires --runtime-image, if this is false - // here then we should have thrown error validating args. - return params.containsKey(PREDEFINED_RUNTIME_IMAGE.getID()); - } - - static boolean hasPredefinedAppImage(Map params) { - return params.containsKey(PREDEFINED_APP_IMAGE.getID()); - } - - private static String getDefaultAppVersion(Map params) { - String appVersion = DEFAULT_VERSION; - - if (isRuntimeInstaller(params)) { - return appVersion; - } - - LauncherData launcherData = null; - try { - launcherData = LAUNCHER_DATA.fetchFrom(params); - } catch (RuntimeException ex) { - if (ex.getCause() instanceof ConfigException) { - return appVersion; - } - throw ex; - } - - if (launcherData.isModular()) { - String moduleVersion = launcherData.getAppVersion(); - if (moduleVersion != null) { - Log.verbose(MessageFormat.format(I18N.getString( - "message.module-version"), - moduleVersion, - launcherData.moduleName())); - appVersion = moduleVersion; - } - } - - return appVersion; - } -} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/TempDirectory.java similarity index 53% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/TempDirectory.java index 762b65b530e..50d1701bf0d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/TempDirectory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 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 @@ -22,36 +22,51 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.jpackage.internal; +import java.io.Closeable; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; -import java.util.Map; +import jdk.jpackage.internal.cli.Options; +import jdk.jpackage.internal.cli.StandardOption; import jdk.jpackage.internal.util.FileUtils; +final class TempDirectory implements Closeable { -/** - * AbstractBundler - * - * This is the base class all bundlers extend from. - * It contains methods and parameters common to all bundlers. - * The concrete implementations are in the platform specific bundlers. - */ -abstract class AbstractBundler implements Bundler { + TempDirectory(Options options) throws IOException { + final var tempDir = StandardOption.TEMP_ROOT.findIn(options); + if (tempDir.isPresent()) { + this.path = tempDir.orElseThrow(); + this.options = options; + } else { + this.path = Files.createTempDirectory("jdk.jpackage"); + this.options = options.copyWithDefaultValue(StandardOption.TEMP_ROOT, path); + } - @Override - public String toString() { - return getName(); + deleteOnClose = tempDir.isEmpty(); + } + + Options options() { + return options; + } + + Path path() { + return path; + } + + boolean deleteOnClose() { + return deleteOnClose; } @Override - public void cleanup(Map params) { - try { - FileUtils.deleteRecursive( - StandardBundlerParam.TEMP_ROOT.fetchFrom(params)); - } catch (IOException e) { - Log.verbose(e.getMessage()); + public void close() throws IOException { + if (deleteOnClose) { + FileUtils.deleteRecursive(path); } } + + private final Path path; + private final Options options; + private final boolean deleteOnClose; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java deleted file mode 100644 index 89a2e4b56fe..00000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2018, 2023, 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 jdk.jpackage.internal; - -import java.util.EnumSet; -import java.util.HashMap; - -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.Arguments.CLIOptions; - -/** - * ValidOptions - * - * Two basic methods for validating command line options. - * - * initArgs() - * Computes the Map of valid options for each mode on this Platform. - * - * checkIfSupported(CLIOptions arg) - * Determine if the given arg is valid on this platform. - * - * checkIfImageSupported(CLIOptions arg) - * Determine if the given arg is valid for creating app image. - * - * checkIfInstallerSupported(CLIOptions arg) - * Determine if the given arg is valid for creating installer. - * - * checkIfSigningSupported(CLIOptions arg) - * Determine if the given arg is valid for signing app image. - * - */ -class ValidOptions { - - enum USE { - ALL, // valid in all cases - LAUNCHER, // valid when creating a launcher - INSTALL, // valid when creating an installer - SIGN, // valid when signing is requested - } - - private static final HashMap> options = new HashMap<>(); - - // initializing list of mandatory arguments - static { - put(CLIOptions.NAME.getId(), USE.ALL); - put(CLIOptions.VERSION.getId(), USE.ALL); - put(CLIOptions.OUTPUT.getId(), USE.ALL); - put(CLIOptions.TEMP_ROOT.getId(), USE.ALL); - put(CLIOptions.VERBOSE.getId(), - EnumSet.of(USE.ALL, USE.SIGN)); - put(CLIOptions.PREDEFINED_RUNTIME_IMAGE.getId(), USE.ALL); - put(CLIOptions.RESOURCE_DIR.getId(), USE.ALL); - put(CLIOptions.DESCRIPTION.getId(), USE.ALL); - put(CLIOptions.VENDOR.getId(), USE.ALL); - put(CLIOptions.COPYRIGHT.getId(), USE.ALL); - put(CLIOptions.PACKAGE_TYPE.getId(), - EnumSet.of(USE.ALL, USE.SIGN)); - put(CLIOptions.ICON.getId(), USE.ALL); - - put(CLIOptions.INPUT.getId(), USE.LAUNCHER); - put(CLIOptions.MODULE.getId(), USE.LAUNCHER); - put(CLIOptions.MODULE_PATH.getId(), USE.LAUNCHER); - put(CLIOptions.ADD_MODULES.getId(), USE.LAUNCHER); - put(CLIOptions.MAIN_JAR.getId(), USE.LAUNCHER); - put(CLIOptions.APPCLASS.getId(), USE.LAUNCHER); - put(CLIOptions.ARGUMENTS.getId(), USE.LAUNCHER); - put(CLIOptions.JAVA_OPTIONS.getId(), USE.LAUNCHER); - put(CLIOptions.ADD_LAUNCHER.getId(), USE.LAUNCHER); - put(CLIOptions.JLINK_OPTIONS.getId(), USE.LAUNCHER); - put(CLIOptions.APP_CONTENT.getId(), USE.LAUNCHER); - - put(CLIOptions.LICENSE_FILE.getId(), USE.INSTALL); - put(CLIOptions.INSTALL_DIR.getId(), USE.INSTALL); - put(CLIOptions.PREDEFINED_APP_IMAGE.getId(), - (OperatingSystem.isMacOS()) ? - EnumSet.of(USE.INSTALL, USE.SIGN) : - EnumSet.of(USE.INSTALL)); - put(CLIOptions.LAUNCHER_AS_SERVICE.getId(), USE.INSTALL); - - put(CLIOptions.ABOUT_URL.getId(), USE.INSTALL); - - put(CLIOptions.FILE_ASSOCIATIONS.getId(), - (OperatingSystem.isMacOS()) ? USE.ALL : USE.INSTALL); - - if (OperatingSystem.isWindows()) { - put(CLIOptions.WIN_CONSOLE_HINT.getId(), USE.LAUNCHER); - - put(CLIOptions.WIN_HELP_URL.getId(), USE.INSTALL); - put(CLIOptions.WIN_UPDATE_URL.getId(), USE.INSTALL); - - put(CLIOptions.WIN_MENU_HINT.getId(), USE.INSTALL); - put(CLIOptions.WIN_MENU_GROUP.getId(), USE.INSTALL); - put(CLIOptions.WIN_SHORTCUT_HINT.getId(), USE.INSTALL); - put(CLIOptions.WIN_SHORTCUT_PROMPT.getId(), USE.INSTALL); - put(CLIOptions.WIN_DIR_CHOOSER.getId(), USE.INSTALL); - put(CLIOptions.WIN_UPGRADE_UUID.getId(), USE.INSTALL); - put(CLIOptions.WIN_PER_USER_INSTALLATION.getId(), - USE.INSTALL); - } - - if (OperatingSystem.isMacOS()) { - put(CLIOptions.MAC_SIGN.getId(), - EnumSet.of(USE.ALL, USE.SIGN)); - put(CLIOptions.MAC_BUNDLE_NAME.getId(), USE.ALL); - put(CLIOptions.MAC_BUNDLE_IDENTIFIER.getId(), USE.ALL); - put(CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId(), - EnumSet.of(USE.ALL, USE.SIGN)); - put(CLIOptions.MAC_SIGNING_KEY_NAME.getId(), - EnumSet.of(USE.ALL, USE.SIGN)); - put(CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId(), - EnumSet.of(USE.ALL, USE.SIGN)); - put(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getId(), - EnumSet.of(USE.INSTALL, USE.SIGN)); - put(CLIOptions.MAC_SIGNING_KEYCHAIN.getId(), - EnumSet.of(USE.ALL, USE.SIGN)); - put(CLIOptions.MAC_APP_STORE.getId(), USE.ALL); - put(CLIOptions.MAC_CATEGORY.getId(), USE.ALL); - put(CLIOptions.MAC_ENTITLEMENTS.getId(), - EnumSet.of(USE.ALL, USE.SIGN)); - put(CLIOptions.DMG_CONTENT.getId(), USE.INSTALL); - } - - if (OperatingSystem.isLinux()) { - put(CLIOptions.LINUX_BUNDLE_NAME.getId(), USE.INSTALL); - put(CLIOptions.LINUX_DEB_MAINTAINER.getId(), USE.INSTALL); - put(CLIOptions.LINUX_CATEGORY.getId(), USE.INSTALL); - put(CLIOptions.LINUX_RPM_LICENSE_TYPE.getId(), USE.INSTALL); - put(CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId(), - USE.INSTALL); - put(CLIOptions.LINUX_MENU_GROUP.getId(), USE.INSTALL); - put(CLIOptions.RELEASE.getId(), USE.INSTALL); - put(CLIOptions.LINUX_SHORTCUT_HINT.getId(), USE.INSTALL); - } - } - - static boolean checkIfSupported(CLIOptions arg) { - return options.containsKey(arg.getId()); - } - - static boolean checkIfImageSupported(CLIOptions arg) { - EnumSet value = options.get(arg.getId()); - return value.contains(USE.ALL) || - value.contains(USE.LAUNCHER) || - value.contains(USE.SIGN); - } - - static boolean checkIfInstallerSupported(CLIOptions arg) { - EnumSet value = options.get(arg.getId()); - return value.contains(USE.ALL) || value.contains(USE.INSTALL); - } - - static boolean checkIfSigningSupported(CLIOptions arg) { - EnumSet value = options.get(arg.getId()); - return value.contains(USE.SIGN); - } - - private static EnumSet put(String key, USE value) { - return options.put(key, EnumSet.of(value)); - } - - private static EnumSet put(String key, EnumSet value) { - return options.put(key, value); - } -} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBuildEnvFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java similarity index 76% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBuildEnvFromParams.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java index 31759c8c529..34019ff9e81 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBuildEnvFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/AdditionalLauncher.java @@ -22,13 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jpackage.internal; -import jdk.jpackage.internal.model.MacPackage; +package jdk.jpackage.internal.cli; -final class MacBuildEnvFromParams { +import java.nio.file.Path; - static final BundlerParamInfo BUILD_ENV = BundlerParamInfo.createBundlerParam(BuildEnv.class, params -> { - return BuildEnvFromParams.create(params, MacPackagingPipeline.APPLICATION_LAYOUT::resolveAt, MacPackage::guessRuntimeLayout); - }); + +record AdditionalLauncher(String name, Path propertyFile) { } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/BundlingOperationModifier.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/BundlingOperationModifier.java new file mode 100644 index 00000000000..33525f3e54d --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/BundlingOperationModifier.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal.cli; + +/** + * Modifiers for jpackage operations. + */ +enum BundlingOperationModifier implements OptionScope { + /** + * Create runtime native bundle. + */ + BUNDLE_RUNTIME, + + /** + * Create native bundle from the predefined app image. + */ + BUNDLE_PREDEFINED_APP_IMAGE, + + ; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/BundlingOperationOptionScope.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/BundlingOperationOptionScope.java new file mode 100644 index 00000000000..04af5865baa --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/BundlingOperationOptionScope.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal.cli; + + +import jdk.jpackage.internal.model.BundlingOperationDescriptor; + +/** + * Bundling operation scope. + *

    + * The scope of bundling operations. E.g., app image or native package bundling. + */ +interface BundlingOperationOptionScope extends OptionScope { + BundlingOperationDescriptor descriptor(); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliBundlingEnvironment.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliBundlingEnvironment.java new file mode 100644 index 00000000000..09ff0997c14 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/CliBundlingEnvironment.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal.cli; + +import java.util.NoSuchElementException; +import jdk.jpackage.internal.model.BundlingEnvironment; +import jdk.jpackage.internal.model.BundlingOperationDescriptor; + +/** + * CLI bundling environment. + */ +public interface CliBundlingEnvironment extends BundlingEnvironment { + + /** + * Requests to run a bundling operation denoted with the given descriptor with + * the given values of command line options. + * + * @param op the descriptor of the requested bundling operation + * @param cmdline the validated values of the command line options + * @throws NoSuchElementException if the specified descriptor is not one of the + * items in the list returned by + * {@link #supportedOperations()} method + */ + void createBundle(BundlingOperationDescriptor op, Options cmdline); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/DefaultOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/DefaultOptions.java new file mode 100644 index 00000000000..91342500277 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/DefaultOptions.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal.cli; + +import static java.util.stream.Collectors.toUnmodifiableMap; +import static java.util.stream.Collectors.toUnmodifiableSet; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + + +final class DefaultOptions implements Options { + + DefaultOptions(Map values) { + this(values, Optional.empty()); + } + + DefaultOptions( + Map values, + Predicate optionNamesFilter) { + + this(values, Optional.of(optionNamesFilter)); + } + + DefaultOptions( + Map values, + Optional> optionNamesFilter) { + + map = values.entrySet().stream().collect(toUnmodifiableMap(e -> { + return e.getKey().id(); + }, e -> { + return new OptionIdentifierWithValue(e.getKey(), e.getValue()); + })); + + var optionNamesStream = optionNames(values.keySet().stream()); + optionNames = optionNamesFilter.map(optionNamesStream::filter).orElse(optionNamesStream) + .collect(toUnmodifiableSet()); + } + + private DefaultOptions(Snapshot snapshot) { + map = snapshot.map(); + optionNames = snapshot.optionNames(); + } + + static DefaultOptions create(Snapshot snapshot) { + var options = new DefaultOptions(snapshot); + + var mapOptionNames = optionNames( + options.map.values().stream().map(OptionIdentifierWithValue::withId) + ).collect(toUnmodifiableSet()); + + for (var e : options.map.entrySet()) { + if (e.getKey() != e.getValue().withId().id()) { + throw new IllegalArgumentException("Corrupted options map"); + } + } + + if (!mapOptionNames.containsAll(snapshot.optionNames())) { + throw new IllegalArgumentException("Unexpected option names"); + } + return options; + } + + @Override + public Optional find(OptionIdentifier id) { + return Optional.ofNullable(map.get(Objects.requireNonNull(id))).map(OptionIdentifierWithValue::value); + } + + @Override + public boolean contains(OptionName optionName) { + return optionNames.contains(Objects.requireNonNull(optionName)); + } + + @Override + public Set ids() { + return Collections.unmodifiableSet(map.keySet()); + } + + @Override + public DefaultOptions copyWithout(Iterable ids) { + return copy(StreamSupport.stream(ids.spliterator(), false), false); + } + + @Override + public DefaultOptions copyWith(Iterable ids) { + return copy(StreamSupport.stream(ids.spliterator(), false), true); + } + + DefaultOptions add(DefaultOptions other) { + return new DefaultOptions(new Snapshot(Stream.of(this, other).flatMap(v -> { + return v.map.values().stream(); + }).collect(toUnmodifiableMap(OptionIdentifierWithValue::id, x -> x, (first, _) -> { + return first; + })), Stream.of(this, other) + .map(DefaultOptions::optionNames) + .flatMap(Collection::stream) + .collect(toUnmodifiableSet()))); + } + + Set optionNames() { + return optionNames; + } + + Set withOptionIdentifierSet() { + return map.values().stream() + .map(OptionIdentifierWithValue::withId) + .collect(toUnmodifiableSet()); + } + + record Snapshot(Map map, Set optionNames) { + Snapshot { + Objects.requireNonNull(map); + Objects.requireNonNull(optionNames); + } + } + + record OptionIdentifierWithValue(WithOptionIdentifier withId, Object value) { + OptionIdentifierWithValue { + Objects.requireNonNull(withId); + Objects.requireNonNull(value); + } + + OptionIdentifier id() { + return withId.id(); + } + + OptionIdentifierWithValue copyWithValue(Object value) { + return new OptionIdentifierWithValue(withId, value); + } + } + + private DefaultOptions copy(Stream ids, boolean includes) { + var includeIds = ids.collect(toUnmodifiableSet()); + return new DefaultOptions(map.values().stream().filter(v -> { + return includeIds.contains(v.id()) == includes; + }).collect(toUnmodifiableMap(OptionIdentifierWithValue::withId, OptionIdentifierWithValue::value))); + } + + private static Stream optionNames(Stream options) { + return options.map(v -> { + Optional> spec; + switch (v) { + case Option option -> { + spec = Optional.of(option.spec()); + } + case OptionValue optionValue -> { + spec = optionValue.asOption().map(Option::spec); + } + default -> { + spec = Optional.empty(); + } + } + return spec; + }).filter(Optional::isPresent).map(Optional::get).map(OptionSpec::names).flatMap(Collection::stream); + } + + static final DefaultOptions EMPTY = new DefaultOptions(Map.of()); + + private final Map map; + private final Set optionNames; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/HelpFormatter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/HelpFormatter.java new file mode 100644 index 00000000000..1d8a5eefc79 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/HelpFormatter.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal.cli; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + + +/** + * Generic help formatter. + */ +final class HelpFormatter { + + private HelpFormatter(List optionGroups, OptionGroupFormatter formatter) { + this.optionGroups = Objects.requireNonNull(optionGroups); + this.formatter = Objects.requireNonNull(formatter); + } + + void format(Consumer sink) { + for (var group : optionGroups) { + formatter.format(group, sink); + } + } + + static Builder build() { + return new Builder(); + } + + + static final class Builder { + + private Builder() { + } + + HelpFormatter create() { + return new HelpFormatter(groups, validatedGroupFormatter()); + } + + Builder groups(Collection v) { + groups.addAll(v); + return this; + } + + Builder groups(OptionGroup... v) { + return groups(List.of(v)); + } + + Builder groupFormatter(OptionGroupFormatter v) { + groupFormatter = v; + return this; + } + + private OptionGroupFormatter validatedGroupFormatter() { + return Optional.ofNullable(groupFormatter).orElseGet(Builder::createConsoleFormatter); + } + + private static OptionGroupFormatter createConsoleFormatter() { + return new ConsoleOptionGroupFormatter(new ConsoleOptionFormatter(2, 10)); + } + + private final List groups = new ArrayList<>(); + private OptionGroupFormatter groupFormatter; + } + + + interface OptionFormatter { + + public default void format(OptionSpec optionSpec, Consumer sink) { + format(optionSpec.names().stream().map(OptionName::formatForCommandLine).collect(Collectors.joining(" ")), + optionSpec.valuePattern(), + optionSpec.description(), sink); + } + + void format(String optionNames, Optional valuePattern, String description, Consumer sink); + } + + interface OptionGroupFormatter { + + default void format(OptionGroup group, Consumer sink) { + formatHeader(group.name(), sink); + formatBody(group.options(), sink); + } + + void formatHeader(String gropName, Consumer sink); + + void formatBody(Iterable> optionSpecs, Consumer sink); + } + + + record ConsoleOptionFormatter(int nameOffset, int descriptionOffset) implements OptionFormatter { + + @Override + public void format(String optionNames, Optional valuePattern, String description, Consumer sink) { + sink.accept(" ".repeat(nameOffset)); + sink.accept(optionNames); + valuePattern.map(v -> " " + v).ifPresent(sink); + eol(sink); + final var descriptionOffsetStr = " ".repeat(descriptionOffset); + Stream.of(description.split("\\R")).map(line -> { + return descriptionOffsetStr + line; + }).forEach(line -> { + sink.accept(line); + eol(sink); + }); + } + } + + + record ConsoleOptionGroupFormatter(OptionFormatter optionFormatter) implements OptionGroupFormatter { + + ConsoleOptionGroupFormatter { + Objects.requireNonNull(optionFormatter); + } + + @Override + public void formatHeader(String groupName, Consumer sink) { + Objects.requireNonNull(groupName); + eol(sink); + sink.accept(groupName + ":"); + eol(sink); + } + + @Override + public void formatBody(Iterable> optionSpecs, Consumer sink) { + optionSpecs.forEach(optionSpec -> { + optionFormatter.format(optionSpec, sink); + }); + } + } + + + record OptionGroup(String name, List> options) { + + OptionGroup { + Objects.requireNonNull(name); + Objects.requireNonNull(options); + } + } + + + static Consumer eol(Consumer sink) { + sink.accept(System.lineSeparator()); + return sink; + } + + + private final List optionGroups; + private final OptionGroupFormatter formatter; +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/I18N.java similarity index 56% rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/I18N.java index 5c912728c32..63c2b88039f 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/I18N.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -22,31 +22,34 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package jdk.jpackage.internal.cli; -package jdk.jpackage.internal; - -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; - +import java.util.List; import java.util.Map; -import jdk.jpackage.internal.model.ConfigException; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.MultiResourceBundle; +import jdk.jpackage.internal.util.StringBundle; -public abstract class MacBaseInstallerBundler extends AbstractBundler { +final class I18N { - public MacBaseInstallerBundler() { - appImageBundler = new MacAppBundler(); + private I18N() { } - protected void validateAppImageAndBundeler( - Map params) throws ConfigException { - if (PREDEFINED_APP_IMAGE.fetchFrom(params) == null) { - appImageBundler.validate(params); - } + static String format(String key, Object ... args) { + return BUNDLE.format(key, args); } - @Override - public String getBundleType() { - return "INSTALLER"; - } + private static final StringBundle BUNDLE; - private final Bundler appImageBundler; + static { + var prefix = "jdk.jpackage.internal.resources."; + BUNDLE = StringBundle.fromResourceBundle(MultiResourceBundle.create( + prefix + "MainResources", + Map.of( + OperatingSystem.LINUX, List.of(prefix + "LinuxResources"), + OperatingSystem.MACOS, List.of(prefix + "MacResources"), + OperatingSystem.WINDOWS, List.of(prefix + "WinResources") + ) + )); + } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/JOptSimpleOptionsBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/JOptSimpleOptionsBuilder.java new file mode 100644 index 00000000000..57b92471e4a --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/JOptSimpleOptionsBuilder.java @@ -0,0 +1,817 @@ +/* + * Copyright (c) 2025, 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 jdk.jpackage.internal.cli; + +import static java.util.stream.Collectors.toUnmodifiableMap; +import static java.util.stream.Collectors.toUnmodifiableSet; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; +import jdk.internal.joptsimple.ArgumentAcceptingOptionSpec; +import jdk.internal.joptsimple.OptionParser; +import jdk.internal.joptsimple.OptionSet; +import jdk.jpackage.internal.cli.DefaultOptions.OptionIdentifierWithValue; +import jdk.jpackage.internal.cli.DefaultOptions.Snapshot; +import jdk.jpackage.internal.cli.OptionSpec.MergePolicy; +import jdk.jpackage.internal.util.Result; + + +/** + * Builds an instance of {@link Options} interface backed with joptsimple command + * line parser. + * + * Two types of command line argument processing are supported: + *
      + *
    1. Parse command line. Parsed data is stored as a map of strings. + *
    2. Convert strings to objects. Parsed data is stored as a map of objects. + *
    + */ +final class JOptSimpleOptionsBuilder { + + Function> create() { + return createJOptSimpleParser()::parse; + } + + JOptSimpleOptionsBuilder options(Collection v) { + v.stream().map(u -> { + switch (u) { + case Option o -> { + return o; + } + case OptionValue ov -> { + return ov.getOption(); + } + default -> { + throw new IllegalArgumentException(); + } + } + }).forEach(options::add); + return this; + } + + JOptSimpleOptionsBuilder options(WithOptionIdentifier... v) { + return options(List.of(v)); + } + + JOptSimpleOptionsBuilder optionSpecMapper(UnaryOperator> v) { + optionSpecMapper = v; + return this; + } + + JOptSimpleOptionsBuilder jOptSimpleParserErrorHandler(Function v) { + jOptSimpleParserErrorHandler = v; + return this; + } + + private JOptSimpleParser createJOptSimpleParser() { + return JOptSimpleParser.create(options, Optional.ofNullable(optionSpecMapper), + Optional.ofNullable(jOptSimpleParserErrorHandler)); + } + + + static final class ConvertedOptionsBuilder { + + private ConvertedOptionsBuilder(TypedOptions options) { + impl = Objects.requireNonNull(options); + } + + Options create() { + return impl; + } + + ConvertedOptionsBuilder copyWithExcludes(Collection v) { + return new ConvertedOptionsBuilder(impl.copyWithout(v)); + } + + List nonOptionArguments() { + return impl.nonOptionArguments(); + } + + List detectedOptions() { + return impl.detectedOptions(); + } + + private final TypedOptions impl; + } + + + static final class OptionsBuilder { + + private OptionsBuilder(UntypedOptions options) { + impl = Objects.requireNonNull(options); + } + + Result convertedOptions() { + return impl.toTypedOptions().map(ConvertedOptionsBuilder::new); + } + + Options create() { + return impl; + } + + OptionsBuilder copyWithExcludes(Collection v) { + return new OptionsBuilder(impl.copyWithout(v)); + } + + List nonOptionArguments() { + return impl.nonOptionArguments(); + } + + List detectedOptions() { + return impl.detectedOptions(); + } + + private final UntypedOptions impl; + } + + + enum JOptSimpleErrorType { + + // jdk.internal.joptsimple.UnrecognizedOptionException + UNRECOGNIZED_OPTION(() -> { + new OptionParser(false).parse("--foo"); + }), + + // jdk.internal.joptsimple.OptionMissingRequiredArgumentException + OPTION_MISSING_REQUIRED_ARGUMENT(() -> { + var parser = new OptionParser(false); + parser.accepts("foo").withRequiredArg(); + parser.parse("--foo"); + }), + ; + + JOptSimpleErrorType(Runnable initializer) { + try { + initializer.run(); + // Should never get to this point as the above line is expected to throw + // an exception of type `jdk.internal.joptsimple.OptionException`. + throw new AssertionError(); + } catch (jdk.internal.joptsimple.OptionException ex) { + type = ex.getClass(); + } + } + + private final Class type; + } + + + record JOptSimpleError(JOptSimpleErrorType type, OptionName optionName) { + + JOptSimpleError { + Objects.requireNonNull(type); + Objects.requireNonNull(optionName); + } + + static JOptSimpleError create(jdk.internal.joptsimple.OptionException ex) { + var optionName = OptionName.of(ex.options().getFirst()); + return Stream.of(JOptSimpleErrorType.values()).filter(v -> { + return v.type.isInstance(ex); + }).findFirst().map(v -> { + return new JOptSimpleError(v, optionName); + }).orElseThrow(); + } + } + + + private record JOptSimpleParser( + OptionParser parser, + Map> optionMap, + Optional> jOptSimpleParserErrorHandler) { + + private JOptSimpleParser { + Objects.requireNonNull(parser); + Objects.requireNonNull(optionMap); + Objects.requireNonNull(jOptSimpleParserErrorHandler); + } + + Result parse(String... args) { + return applyParser(parser, args).map(optionSet -> { + final OptionSet mergerOptionSet; + if (optionMap.values().stream().allMatch(spec -> spec.names().size() == 1)) { + // No specs with multiple names, merger not needed. + mergerOptionSet = optionSet; + } else { + final var parser2 = createOptionParser(); + final var optionSpecApplier = new OptionSpecApplier(); + for (final var spec : optionMap.values()) { + optionSpecApplier.applyToParser(parser2, spec); + } + + mergerOptionSet = parser2.parse(args); + } + return new OptionsBuilder(new UntypedOptions(optionSet, mergerOptionSet, optionMap)); + }); + } + + static JOptSimpleParser create(Iterable