From 97bd6da6c6301892e14a6067711cdae5fc251754 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Tue, 16 Jun 2015 14:58:30 +0100 Subject: [PATCH 01/21] 8130150: Implement BigInteger.montgomeryMultiply intrinsic Add montgomeryMultiply intrinsics Reviewed-by: kvn --- .../share/classes/java/math/BigInteger.java | 116 +++++++++++++++--- .../classes/java/math/MutableBigInteger.java | 15 +++ 2 files changed, 117 insertions(+), 14 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/math/BigInteger.java b/jdk/src/java.base/share/classes/java/math/BigInteger.java index 3b3cbf50739..51ed2b6abbf 100644 --- a/jdk/src/java.base/share/classes/java/math/BigInteger.java +++ b/jdk/src/java.base/share/classes/java/math/BigInteger.java @@ -262,6 +262,15 @@ public class BigInteger extends Number implements Comparable { */ private static final int MULTIPLY_SQUARE_THRESHOLD = 20; + /** + * The threshold for using an intrinsic version of + * implMontgomeryXXX to perform Montgomery multiplication. If the + * number of ints in the number is more than this value we do not + * use the intrinsic. + */ + private static final int MONTGOMERY_INTRINSIC_THRESHOLD = 512; + + // Constructors /** @@ -1639,7 +1648,7 @@ public class BigInteger extends Number implements Comparable { * Multiplies int arrays x and y to the specified lengths and places * the result into z. There will be no leading zeros in the resultant array. */ - private int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) { + private static int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) { int xstart = xlen - 1; int ystart = ylen - 1; @@ -2601,6 +2610,75 @@ public class BigInteger extends Number implements Comparable { return (invertResult ? result.modInverse(m) : result); } + // Montgomery multiplication. These are wrappers for + // implMontgomeryXX routines which are expected to be replaced by + // virtual machine intrinsics. We don't use the intrinsics for + // very large operands: MONTGOMERY_INTRINSIC_THRESHOLD should be + // larger than any reasonable crypto key. + private static int[] montgomeryMultiply(int[] a, int[] b, int[] n, int len, long inv, + int[] product) { + implMontgomeryMultiplyChecks(a, b, n, len, product); + if (len > MONTGOMERY_INTRINSIC_THRESHOLD) { + // Very long argument: do not use an intrinsic + product = multiplyToLen(a, len, b, len, product); + return montReduce(product, n, len, (int)inv); + } else { + return implMontgomeryMultiply(a, b, n, len, inv, materialize(product, len)); + } + } + private static int[] montgomerySquare(int[] a, int[] n, int len, long inv, + int[] product) { + implMontgomeryMultiplyChecks(a, a, n, len, product); + if (len > MONTGOMERY_INTRINSIC_THRESHOLD) { + // Very long argument: do not use an intrinsic + product = squareToLen(a, len, product); + return montReduce(product, n, len, (int)inv); + } else { + return implMontgomerySquare(a, n, len, inv, materialize(product, len)); + } + } + + // Range-check everything. + private static void implMontgomeryMultiplyChecks + (int[] a, int[] b, int[] n, int len, int[] product) throws RuntimeException { + if (len % 2 != 0) { + throw new IllegalArgumentException("input array length must be even: " + len); + } + + if (len < 1) { + throw new IllegalArgumentException("invalid input length: " + len); + } + + if (len > a.length || + len > b.length || + len > n.length || + (product != null && len > product.length)) { + throw new IllegalArgumentException("input array length out of bound: " + len); + } + } + + // Make sure that the int array z (which is expected to contain + // the result of a Montgomery multiplication) is present and + // sufficiently large. + private static int[] materialize(int[] z, int len) { + if (z == null || z.length < len) + z = new int[len]; + return z; + } + + // These methods are intended to be be replaced by virtual machine + // intrinsics. + private static int[] implMontgomeryMultiply(int[] a, int[] b, int[] n, int len, + long inv, int[] product) { + product = multiplyToLen(a, len, b, len, product); + return montReduce(product, n, len, (int)inv); + } + private static int[] implMontgomerySquare(int[] a, int[] n, int len, + long inv, int[] product) { + product = squareToLen(a, len, product); + return montReduce(product, n, len, (int)inv); + } + static int[] bnExpModThreshTable = {7, 25, 81, 241, 673, 1793, Integer.MAX_VALUE}; // Sentinel @@ -2679,6 +2757,17 @@ public class BigInteger extends Number implements Comparable { int[] mod = z.mag; int modLen = mod.length; + // Make modLen even. It is conventional to use a cryptographic + // modulus that is 512, 768, 1024, or 2048 bits, so this code + // will not normally be executed. However, it is necessary for + // the correct functioning of the HotSpot intrinsics. + if ((modLen & 1) != 0) { + int[] x = new int[modLen + 1]; + System.arraycopy(mod, 0, x, 1, modLen); + mod = x; + modLen++; + } + // Select an appropriate window size int wbits = 0; int ebits = bitLength(exp, exp.length); @@ -2697,8 +2786,10 @@ public class BigInteger extends Number implements Comparable { for (int i=0; i < tblmask; i++) table[i] = new int[modLen]; - // Compute the modular inverse - int inv = -MutableBigInteger.inverseMod32(mod[modLen-1]); + // Compute the modular inverse of the least significant 64-bit + // digit of the modulus + long n0 = (mod[modLen-1] & LONG_MASK) + ((mod[modLen-2] & LONG_MASK) << 32); + long inv = -MutableBigInteger.inverseMod64(n0); // Convert base to Montgomery form int[] a = leftShift(base, base.length, modLen << 5); @@ -2706,6 +2797,8 @@ public class BigInteger extends Number implements Comparable { MutableBigInteger q = new MutableBigInteger(), a2 = new MutableBigInteger(a), b2 = new MutableBigInteger(mod); + b2.normalize(); // MutableBigInteger.divide() assumes that its + // divisor is in normal form. MutableBigInteger r= a2.divide(b2, q); table[0] = r.toIntArray(); @@ -2714,22 +2807,19 @@ public class BigInteger extends Number implements Comparable { if (table[0].length < modLen) { int offset = modLen - table[0].length; int[] t2 = new int[modLen]; - for (int i=0; i < table[0].length; i++) - t2[i+offset] = table[0][i]; + System.arraycopy(table[0], 0, t2, offset, table[0].length); table[0] = t2; } // Set b to the square of the base - int[] b = squareToLen(table[0], modLen, null); - b = montReduce(b, mod, modLen, inv); + int[] b = montgomerySquare(table[0], mod, modLen, inv, null); // Set t to high half of b int[] t = Arrays.copyOf(b, modLen); // Fill in the table with odd powers of the base for (int i=1; i < tblmask; i++) { - int[] prod = multiplyToLen(t, modLen, table[i-1], modLen, null); - table[i] = montReduce(prod, mod, modLen, inv); + table[i] = montgomeryMultiply(t, table[i-1], mod, modLen, inv, null); } // Pre load the window that slides over the exponent @@ -2800,8 +2890,7 @@ public class BigInteger extends Number implements Comparable { isone = false; } else { t = b; - a = multiplyToLen(t, modLen, mult, modLen, a); - a = montReduce(a, mod, modLen, inv); + a = montgomeryMultiply(t, mult, mod, modLen, inv, a); t = a; a = b; b = t; } } @@ -2813,8 +2902,7 @@ public class BigInteger extends Number implements Comparable { // Square the input if (!isone) { t = b; - a = squareToLen(t, modLen, a); - a = montReduce(a, mod, modLen, inv); + a = montgomerySquare(t, mod, modLen, inv, a); t = a; a = b; b = t; } } @@ -2823,7 +2911,7 @@ public class BigInteger extends Number implements Comparable { int[] t2 = new int[2*modLen]; System.arraycopy(b, 0, t2, modLen, modLen); - b = montReduce(t2, mod, modLen, inv); + b = montReduce(t2, mod, modLen, (int)inv); t2 = Arrays.copyOf(b, modLen); diff --git a/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java b/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java index 00e95aad8ec..73a244fd5b4 100644 --- a/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java +++ b/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java @@ -2064,6 +2064,21 @@ class MutableBigInteger { return t; } + /** + * Returns the multiplicative inverse of val mod 2^64. Assumes val is odd. + */ + static long inverseMod64(long val) { + // Newton's iteration! + long t = val; + t *= 2 - val*t; + t *= 2 - val*t; + t *= 2 - val*t; + t *= 2 - val*t; + t *= 2 - val*t; + assert(t * val == 1); + return t; + } + /** * Calculate the multiplicative inverse of 2^k mod mod, where mod is odd. */ From c8358923f7ce7e8ab9dfb5f05cd26f60a5523150 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Mon, 22 Jun 2015 15:43:40 +0300 Subject: [PATCH 02/21] 8129116: Deadlock with multimonitor fullscreen windows Reviewed-by: alexsch, serb --- .../unix/classes/sun/awt/X11/XWindowPeer.java | 45 +++++++------ .../MultimonDeadlockTest.java | 66 +++++++++++++++++++ 2 files changed, 91 insertions(+), 20 deletions(-) create mode 100644 jdk/test/java/awt/FullScreen/MultimonFullscreenTest/MultimonDeadlockTest.java diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java index 585185308df..4a948698705 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java @@ -682,28 +682,33 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, GraphicsConfiguration newGC = null; Rectangle screenBounds; - for (int i = 0; i < gds.length; i++) { - screenBounds = gds[i].getDefaultConfiguration().getBounds(); - if (newBounds.intersects(screenBounds)) { - horizAmt = Math.min(newBounds.x + newBounds.width, - screenBounds.x + screenBounds.width) - - Math.max(newBounds.x, screenBounds.x); - vertAmt = Math.min(newBounds.y + newBounds.height, - screenBounds.y + screenBounds.height)- - Math.max(newBounds.y, screenBounds.y); - intAmt = horizAmt * vertAmt; - if (intAmt == area) { - // Completely on this screen - done! - newScreenNum = i; - newGC = gds[i].getDefaultConfiguration(); - break; - } - if (intAmt > largestAmt) { - largestAmt = intAmt; - newScreenNum = i; - newGC = gds[i].getDefaultConfiguration(); + XToolkit.awtUnlock(); + try { + for (int i = 0; i < gds.length; i++) { + screenBounds = gds[i].getDefaultConfiguration().getBounds(); + if (newBounds.intersects(screenBounds)) { + horizAmt = Math.min(newBounds.x + newBounds.width, + screenBounds.x + screenBounds.width) - + Math.max(newBounds.x, screenBounds.x); + vertAmt = Math.min(newBounds.y + newBounds.height, + screenBounds.y + screenBounds.height)- + Math.max(newBounds.y, screenBounds.y); + intAmt = horizAmt * vertAmt; + if (intAmt == area) { + // Completely on this screen - done! + newScreenNum = i; + newGC = gds[i].getDefaultConfiguration(); + break; + } + if (intAmt > largestAmt) { + largestAmt = intAmt; + newScreenNum = i; + newGC = gds[i].getDefaultConfiguration(); + } } } + } finally { + XToolkit.awtLock(); } if (newScreenNum != curScreenNum) { if (log.isLoggable(PlatformLogger.Level.FINEST)) { diff --git a/jdk/test/java/awt/FullScreen/MultimonFullscreenTest/MultimonDeadlockTest.java b/jdk/test/java/awt/FullScreen/MultimonFullscreenTest/MultimonDeadlockTest.java new file mode 100644 index 00000000000..c457245c3f1 --- /dev/null +++ b/jdk/test/java/awt/FullScreen/MultimonFullscreenTest/MultimonDeadlockTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 8129116 + @summary Deadlock with multimonitor fullscreen windows. + @run main/timeout=20 MultimonDeadlockTest + */ +import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; + +public class MultimonDeadlockTest { + + public static void main(String argv[]) { + final GraphicsDevice[] devices = GraphicsEnvironment + .getLocalGraphicsEnvironment() + .getScreenDevices(); + if (devices.length < 2) { + System.out.println("It's a multiscreen test... skipping!"); + return; + } + + Frame frames[] = new Frame[devices.length]; + try { + EventQueue.invokeAndWait(() -> { + for (int i = 0; i < devices.length; i++) { + frames[i] = new Frame(); + frames[i].setSize(100, 100); + frames[i].setBackground(Color.BLUE); + devices[i].setFullScreenWindow(frames[i]); + } + }); + Thread.sleep(5000); + } catch (InterruptedException | InvocationTargetException ex) { + } finally { + for (int i = 0; i < devices.length; i++) { + devices[i].setFullScreenWindow(null); + frames[i].dispose(); + } + } + + } +} From 3d7db7c9f57c672e6c4873e321bb936c41387798 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Mon, 22 Jun 2015 15:47:44 +0300 Subject: [PATCH 03/21] 8081371: [PIT] Test closed/java/awt/FullScreen/DisplayMode/CycleDMImage.java switches Linux to the single device mode Reviewed-by: alexsch, serb --- .../unix/classes/sun/awt/X11GraphicsDevice.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java index a80994eef96..c6b9cc94044 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java @@ -284,7 +284,6 @@ public final class X11GraphicsDevice extends GraphicsDevice * Returns true only if: * - the Xrandr extension is present * - the necessary Xrandr functions were loaded successfully - * - XINERAMA is not enabled */ private static synchronized boolean isXrandrExtensionSupported() { if (xrandrExtSupported == null) { @@ -316,7 +315,9 @@ public final class X11GraphicsDevice extends GraphicsDevice @Override public boolean isDisplayChangeSupported() { - return (isFullScreenSupported() && (getFullScreenWindow() != null)); + return (isFullScreenSupported() + && !((X11GraphicsEnvironment) GraphicsEnvironment + .getLocalGraphicsEnvironment()).runningXinerama()); } private static void enterFullScreenExclusive(Window w) { @@ -346,7 +347,9 @@ public final class X11GraphicsDevice extends GraphicsDevice if (fsSupported && old != null) { // enter windowed mode (and restore original display mode) exitFullScreenExclusive(old); - setDisplayMode(origDisplayMode); + if (isDisplayChangeSupported()) { + setDisplayMode(origDisplayMode); + } } super.setFullScreenWindow(w); @@ -428,7 +431,9 @@ public final class X11GraphicsDevice extends GraphicsDevice Window old = getFullScreenWindow(); if (old != null) { exitFullScreenExclusive(old); - setDisplayMode(origDisplayMode); + if (isDisplayChangeSupported()) { + setDisplayMode(origDisplayMode); + } } }; String name = "Display-Change-Shutdown-Thread-" + screen; From b95fa126c32aa0441853a322decd410b442ac0f2 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 24 Jun 2015 11:59:11 -0700 Subject: [PATCH 04/21] 8129386: [TESTBUG] - com/sun/jdi/cds/*.java missing @build tag for libraries Added @build tags for all dependent classes Reviewed-by: iklam, mseledtsov, dholmes --- jdk/test/com/sun/jdi/cds/CDSBreakpointTest.java | 3 +++ jdk/test/com/sun/jdi/cds/CDSDeleteAllBkptsTest.java | 3 +++ jdk/test/com/sun/jdi/cds/CDSFieldWatchpoints.java | 3 +++ 3 files changed, 9 insertions(+) diff --git a/jdk/test/com/sun/jdi/cds/CDSBreakpointTest.java b/jdk/test/com/sun/jdi/cds/CDSBreakpointTest.java index fe07abd8f1c..cf597cc527d 100644 --- a/jdk/test/com/sun/jdi/cds/CDSBreakpointTest.java +++ b/jdk/test/com/sun/jdi/cds/CDSBreakpointTest.java @@ -31,6 +31,9 @@ * jdk.jartool/sun.tools.jar * @library /lib/testlibrary * @library .. + * @build jdk.testlibrary.* + * @build TestScaffold VMConnection TargetListener TargetAdapter + * @build CDSJDITest * @run compile -g ../BreakpointTest.java * @run main CDSBreakpointTest */ diff --git a/jdk/test/com/sun/jdi/cds/CDSDeleteAllBkptsTest.java b/jdk/test/com/sun/jdi/cds/CDSDeleteAllBkptsTest.java index 1f03cacd681..0bc2eb3b3fc 100644 --- a/jdk/test/com/sun/jdi/cds/CDSDeleteAllBkptsTest.java +++ b/jdk/test/com/sun/jdi/cds/CDSDeleteAllBkptsTest.java @@ -31,6 +31,9 @@ * jdk.jartool/sun.tools.jar * @library /lib/testlibrary * @library .. + * @build jdk.testlibrary.* + * @build TestScaffold VMConnection TargetListener TargetAdapter + * @build CDSJDITest * @run compile -g ../DeleteAllBkptsTest.java * @run main CDSDeleteAllBkptsTest */ diff --git a/jdk/test/com/sun/jdi/cds/CDSFieldWatchpoints.java b/jdk/test/com/sun/jdi/cds/CDSFieldWatchpoints.java index dcb4145d3ae..1b5a5e44b95 100644 --- a/jdk/test/com/sun/jdi/cds/CDSFieldWatchpoints.java +++ b/jdk/test/com/sun/jdi/cds/CDSFieldWatchpoints.java @@ -31,6 +31,9 @@ * jdk.jartool/sun.tools.jar * @library /lib/testlibrary * @library .. + * @build jdk.testlibrary.* + * @build TestScaffold VMConnection TargetListener TargetAdapter + * @build CDSJDITest * @run compile -g ../FieldWatchpoints.java * @run main CDSFieldWatchpoints */ From 30cacaa5c9017d34693008a102e0eea66cd80e2d Mon Sep 17 00:00:00 2001 From: Jean-Francois Denise Date: Thu, 25 Jun 2015 18:24:39 +0200 Subject: [PATCH 05/21] 8080511: Refresh of jimage support Co-authored-by: James Laskey Co-authored-by: Sundararajan Athijegannathan Reviewed-by: alanb, mchung, psandoz, acorn, lfoltan, ctornqvi --- jdk/make/Tools.gmk | 1 - jdk/make/mapfiles/libjava/mapfile-vers | 13 +- .../build/tools/module/ImageBuilder.java | 146 +++--- .../build/tools/module/ModuleArchive.java | 257 ++++------ .../classes/jdk/internal/jimage/Archive.java | 89 +++- .../jdk/internal/jimage/BasicImageReader.java | 294 ++++++----- .../jdk/internal/jimage/BasicImageWriter.java | 225 +++------ .../internal/jimage/ExternalFilesWriter.java | 105 ++++ .../jdk/internal/jimage/ImageBufferCache.java | 123 +++++ .../jdk/internal/jimage/ImageFile.java | 288 ----------- .../jdk/internal/jimage/ImageFileCreator.java | 355 +++++++++++++ .../jdk/internal/jimage/ImageHeader.java | 91 ++-- .../internal/jimage/ImageJavaSubstrate.java | 242 +++++++++ .../jdk/internal/jimage/ImageLocation.java | 368 +------------- .../internal/jimage/ImageLocationBase.java | 264 ++++++++++ .../internal/jimage/ImageLocationWriter.java | 140 ++++++ .../jdk/internal/jimage/ImageModuleData.java | 288 +++++++++++ .../jimage/ImageModuleDataWriter.java | 165 ++++++ .../jdk/internal/jimage/ImageModules.java | 180 ------- .../internal/jimage/ImageNativeSubstrate.java | 134 +++++ .../jdk/internal/jimage/ImageReader.java | 471 ++++++++++++------ .../internal/jimage/ImageReaderFactory.java | 79 +++ .../internal/jimage/ImageResourcesTree.java | 344 +++++++++++++ .../jdk/internal/jimage/ImageStream.java | 2 +- .../jdk/internal/jimage/ImageStrings.java | 81 +-- ...{Resource.java => ImageStringsReader.java} | 47 +- .../internal/jimage/ImageStringsWriter.java | 105 ++++ ...kageModuleMap.java => ImageSubstrate.java} | 49 +- .../classes/jdk/internal/jimage/PReader.java | 139 ------ .../internal/jimage/PerfectHashBuilder.java | 255 ++++++++++ .../jdk/internal/jimage/ResourcePool.java | 256 ++++++++++ .../jdk/internal/jimage/ResourcePoolImpl.java | 211 ++++++++ .../jdk/internal/jimage/StringTable.java | 44 ++ .../jdk/internal/jimage/UTF8String.java | 44 +- .../jimage/concurrent/ConcurrentPReader.java | 149 ------ .../CompressedResourceHeader.java | 124 +++++ .../jimage/decompressor/Decompressor.java | 97 ++++ .../decompressor/ResourceDecompressor.java | 53 ++ .../ResourceDecompressorFactory.java | 80 +++ .../ResourceDecompressorRepository.java | 70 +++ .../jimage/decompressor/ZipDecompressor.java | 79 +++ .../decompressor/ZipDecompressorFactory.java | 45 ++ .../internal/jrtfs/JrtDirectoryStream.java | 2 +- .../internal/jrtfs/JrtFileAttributeView.java | 19 +- .../jdk/internal/jrtfs/JrtFileAttributes.java | 4 +- .../jdk/internal/jrtfs/JrtFileSystem.java | 216 ++++++-- .../internal/jrtfs/JrtFileSystemProvider.java | 9 +- .../classes/jdk/internal/jrtfs/JrtPath.java | 28 +- .../jdk/internal/jrtfs/SystemImages.java | 1 + jdk/src/java.base/share/native/include/jvm.h | 42 ++ .../java.base/share/native/libjava/Image.c | 177 +++++++ .../native/libjava/ConcurrentPReader_md.c | 66 --- .../native/libjava/ConcurrentPReader_md.c | 64 --- .../jdk/tools/jimage/ExtractedImage.java | 210 ++++++++ .../classes/jdk/tools/jimage/JImageTask.java | 434 +++++----------- .../classes/jdk/tools/jimage/TaskHelper.java | 231 +++++++++ .../tools/jimage/resources/jimage.properties | 36 +- .../classes/sun/tools/java/ClassPath.java | 2 +- .../FieldSetAccessibleTest.java | 4 +- jdk/test/java/nio/Buffer/LimitDirectMemory.sh | 1 + .../Charset/NIOCharsetAvailabilityTest.java | 6 +- .../java/nio/file/spi/SetDefaultProvider.java | 1 + .../jdk/internal/jimage/VerifyJimage.java | 7 +- jdk/test/jdk/internal/jrtfs/Basic.java | 268 +++++++--- .../internal/jrtfs/WithSecurityManager.java | 9 +- 65 files changed, 5817 insertions(+), 2612 deletions(-) create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ExternalFilesWriter.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageBufferCache.java delete mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageFile.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageFileCreator.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageJavaSubstrate.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocationBase.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocationWriter.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleData.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleDataWriter.java delete mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModules.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageResourcesTree.java rename jdk/src/java.base/share/classes/jdk/internal/jimage/{Resource.java => ImageStringsReader.java} (60%) create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStringsWriter.java rename jdk/src/java.base/share/classes/jdk/internal/jimage/{PackageModuleMap.java => ImageSubstrate.java} (55%) delete mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/PReader.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/PerfectHashBuilder.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePool.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePoolImpl.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/StringTable.java delete mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/concurrent/ConcurrentPReader.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressedResourceHeader.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/Decompressor.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressor.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java create mode 100644 jdk/src/java.base/share/native/libjava/Image.c delete mode 100644 jdk/src/java.base/unix/native/libjava/ConcurrentPReader_md.c delete mode 100644 jdk/src/java.base/windows/native/libjava/ConcurrentPReader_md.c create mode 100644 jdk/src/jdk.dev/share/classes/jdk/tools/jimage/ExtractedImage.java create mode 100644 jdk/src/jdk.dev/share/classes/jdk/tools/jimage/TaskHelper.java diff --git a/jdk/make/Tools.gmk b/jdk/make/Tools.gmk index 0d56ccbb827..5e8fd6efdbf 100644 --- a/jdk/make/Tools.gmk +++ b/jdk/make/Tools.gmk @@ -144,7 +144,6 @@ $(eval $(call SetupJavaCompilation,BUILD_INTERIM_JIMAGE, \ SETUP := GENERATE_OLDBYTECODE, \ SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \ INCLUDES := $(JIMAGE_PKGS), \ - EXCLUDES := jdk/internal/jimage/concurrent, \ BIN := $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes)) # Because of the explicit INCLUDES in the compilation setup above, the service provider diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers index 855ac081431..c8d176709df 100644 --- a/jdk/make/mapfiles/libjava/mapfile-vers +++ b/jdk/make/mapfiles/libjava/mapfile-vers @@ -239,6 +239,16 @@ SUNWprivate_1.1 { Java_java_util_TimeZone_getSystemTimeZoneID; Java_java_util_TimeZone_getSystemGMTOffsetID; Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8; + Java_jdk_internal_jimage_ImageNativeSubstrate_openImage; + Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage; + Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress; + Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress; + Java_jdk_internal_jimage_ImageNativeSubstrate_read; + Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed; + Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes; + Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes; + Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes; + Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets; Java_sun_misc_MessageUtils_toStderr; Java_sun_misc_MessageUtils_toStdout; Java_sun_misc_NativeSignalHandler_handle0; @@ -281,9 +291,6 @@ SUNWprivate_1.1 { Java_sun_misc_VMSupport_initAgentProperties; Java_sun_misc_VMSupport_getVMTemporaryDirectory; - Java_jdk_internal_jimage_concurrent_ConcurrentPReader_initIDs; - Java_jdk_internal_jimage_concurrent_ConcurrentPReader_pread; - # ZipFile.c needs this one throwFileNotFoundException; # zip_util.c needs this one diff --git a/jdk/make/src/classes/build/tools/module/ImageBuilder.java b/jdk/make/src/classes/build/tools/module/ImageBuilder.java index e9de90b8e5b..b87d59306c2 100644 --- a/jdk/make/src/classes/build/tools/module/ImageBuilder.java +++ b/jdk/make/src/classes/build/tools/module/ImageBuilder.java @@ -26,8 +26,6 @@ package build.tools.module; import jdk.internal.jimage.Archive; -import jdk.internal.jimage.ImageFile; -import jdk.internal.jimage.ImageModules; import java.io.BufferedReader; import java.io.File; @@ -35,13 +33,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; -import java.io.UncheckedIOException; import java.nio.ByteOrder; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.attribute.PosixFilePermission; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -52,6 +48,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import jdk.internal.jimage.ImageFileCreator; /** * A tool for building a runtime image. @@ -84,11 +81,23 @@ class ImageBuilder { boolean showUsage; } - static abstract class Option { + static class Option { + + interface Processing { + + void process(ImageBuilder task, String opt, String arg) throws BadArgs; + } + final boolean hasArg; final String[] aliases; - Option(boolean hasArg, String... aliases) { + final String description; + final Processing processing; + + Option(boolean hasArg, String description, Processing processing, + String... aliases) { this.hasArg = hasArg; + this.description = description; + this.processing = processing; this.aliases = aliases; } boolean isHidden() { @@ -107,8 +116,12 @@ class ImageBuilder { boolean ignoreRest() { return false; } - abstract void process(ImageBuilder task, String opt, String arg) throws BadArgs; - abstract String description(); + void process(ImageBuilder task, String opt, String arg) throws BadArgs { + processing.process(task, opt, arg); + } + String description() { + return description; + } } private static Path CWD = Paths.get(""); @@ -133,64 +146,44 @@ class ImageBuilder { } static Option[] recognizedOptions = { - new Option(true, "--cmds") { - void process(ImageBuilder task, String opt, String arg) throws BadArgs { - task.options.cmds = splitPath(arg, File.pathSeparator); - } - String description() { return "Location of native commands"; } - }, - new Option(true, "--configs") { - void process(ImageBuilder task, String opt, String arg) throws BadArgs { - task.options.configs = splitPath(arg, File.pathSeparator); - } - String description() { return "Location of config files"; } - }, - new Option(false, "--help") { - void process(ImageBuilder task, String opt, String arg) { - task.options.help = true; - } - String description() { return "Print this usage message"; } - }, - new Option(true, "--classes") { - void process(ImageBuilder task, String opt, String arg) throws BadArgs { - task.options.classes = splitPath(arg, File.pathSeparator); - } - String description() { return "Location of module classes files"; } - }, - new Option(true, "--libs") { - void process(ImageBuilder task, String opt, String arg) throws BadArgs { - task.options.libs = splitPath(arg, File.pathSeparator); - } - String description() { return "Location of native libraries"; } - }, - new Option(true, "--mods") { - void process(ImageBuilder task, String opt, String arg) throws BadArgs { - for (String mn : arg.split(",")) { - if (mn.isEmpty()) - throw new BadArgs("Module not found", mn); - task.options.mods.add(mn); + new Option(true, "Location of native commands", (task, opt, arg) -> { + task.options.cmds = splitPath(arg, File.pathSeparator); + }, "--cmds"), + new Option(true, "Location of config files", (task, opt, arg) -> { + task.options.configs = splitPath(arg, File.pathSeparator); + }, "--configs"), + new Option(false, "Print this usage message", (task, opt, arg) -> { + task.options.help = true; + }, "--help"), + new Option(true, "Location of module classes files", (task, opt, arg) -> { + task.options.classes = splitPath(arg, File.pathSeparator); + }, "--classes"), + new Option(true, "Location of native libraries", (task, opt, arg) -> { + task.options.libs = splitPath(arg, File.pathSeparator); + }, "--libs"), + new Option(true, "Comma separated list of module names", + (task, opt, arg) -> { + for (String mn : arg.split(",")) { + if (mn.isEmpty()) { + throw new BadArgs("Module not found", mn); } + task.options.mods.add(mn); } - String description() { return "Comma separated list of module names"; } - }, - new Option(true, "--output") { - void process(ImageBuilder task, String opt, String arg) throws BadArgs { - Path path = Paths.get(arg); - task.options.output = path; + }, "--mods"), + new Option(true, "Location of the output path", (task, opt, arg) -> { + Path path = Paths.get(arg); + task.options.output = path; + }, "--output"), + new Option(true, "Byte order of the target runtime; {little,big}", + (task, opt, arg) -> { + if (arg.equals("little")) { + task.options.endian = ByteOrder.LITTLE_ENDIAN; + } else if (arg.equals("big")) { + task.options.endian = ByteOrder.BIG_ENDIAN; + } else { + throw new BadArgs("Unknown byte order " + arg); } - String description() { return "Location of the output path"; } - }, - new Option(true, "--endian") { - void process(ImageBuilder task, String opt, String arg) throws BadArgs { - if (arg.equals("little")) - task.options.endian = ByteOrder.LITTLE_ENDIAN; - else if (arg.equals("big")) - task.options.endian = ByteOrder.BIG_ENDIAN; - else - throw new BadArgs("Unknown byte order " + arg); - } - String description() { return "Byte order of the target runtime; {little,big}"; } - } + }, "--endian") }; private final Options options = new Options(); @@ -370,28 +363,35 @@ class ImageBuilder { final Set bootModules; final Set extModules; final Set appModules; - final ImageModules imf; ImageFileHelper(Collection modules) throws IOException { this.modules = modules; this.bootModules = modulesFor(BOOT_MODULES).stream() - .filter(modules::contains) - .collect(Collectors.toSet()); + .filter(modules::contains) + .collect(Collectors.toSet()); this.extModules = modulesFor(EXT_MODULES).stream() .filter(modules::contains) .collect(Collectors.toSet()); this.appModules = modules.stream() - .filter(m -> !bootModules.contains(m) && !extModules.contains(m)) + .filter(m -> m.length() != 0 && + !bootModules.contains(m) && + !extModules.contains(m)) .collect(Collectors.toSet()); - - this.imf = new ImageModules(bootModules, extModules, appModules); } void createModularImage(Path output) throws IOException { - Set archives = modules.stream() - .map(this::toModuleArchive) - .collect(Collectors.toSet()); - ImageFile.create(output, archives, imf, options.endian); + Set bootArchives = bootModules.stream() + .map(this::toModuleArchive) + .collect(Collectors.toSet()); + Set extArchives = extModules.stream() + .map(this::toModuleArchive) + .collect(Collectors.toSet()); + Set appArchives = appModules.stream() + .map(this::toModuleArchive) + .collect(Collectors.toSet()); + ImageFileCreator.create(output, "bootmodules", bootArchives, options.endian); + ImageFileCreator.create(output, "extmodules", extArchives, options.endian); + ImageFileCreator.create(output, "appmodules", appArchives, options.endian); } ModuleArchive toModuleArchive(String mn) { diff --git a/jdk/make/src/classes/build/tools/module/ModuleArchive.java b/jdk/make/src/classes/build/tools/module/ModuleArchive.java index 716e8b99361..2e1eb7ab148 100644 --- a/jdk/make/src/classes/build/tools/module/ModuleArchive.java +++ b/jdk/make/src/classes/build/tools/module/ModuleArchive.java @@ -26,15 +26,17 @@ package build.tools.module; import jdk.internal.jimage.Archive; -import jdk.internal.jimage.Resource; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.function.Consumer; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.internal.jimage.Archive.Entry.EntryType; /** * An Archive backed by an exploded representation on disk. @@ -46,6 +48,8 @@ public class ModuleArchive implements Archive { private final Path configs; private final String moduleName; + private final List opened = new ArrayList<>(); + public ModuleArchive(String moduleName, Path classes, Path cmds, Path libs, Path configs) { this.moduleName = moduleName; @@ -61,182 +65,119 @@ public class ModuleArchive implements Archive { } @Override - public void visitResources(Consumer consumer) { - if (classes == null) - return; - try{ - Files.walk(classes) - .sorted() - .filter(p -> !Files.isDirectory(p) - && !classes.relativize(p).toString().startsWith("_the.") - && !classes.relativize(p).toString().equals("javac_state")) - .map(this::toResource) - .forEach(consumer::accept); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - } - - private Resource toResource(Path path) { - try { - return new Resource(classes.relativize(path).toString().replace('\\','/'), - Files.size(path), - 0 /* no compression support yet */); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - } - - private enum Section { - CLASSES, - CMDS, - LIBS, - CONFIGS + public void open() throws IOException { + // NOOP } @Override - public void visitEntries(Consumer consumer) { - try{ - if (classes != null) - Files.walk(classes) - .sorted() - .filter(p -> !Files.isDirectory(p) - && !classes.relativize(p).toString().startsWith("_the.") - && !classes.relativize(p).toString().equals("javac_state")) - .map(p -> toEntry(p, classes, Section.CLASSES)) - .forEach(consumer::accept); - if (cmds != null) - Files.walk(cmds) + public void close() throws IOException { + IOException e = null; + for (InputStream stream : opened) { + try { + stream.close(); + } catch (IOException ex) { + if (e == null) { + e = ex; + } else { + e.addSuppressed(ex); + } + } + } + if (e != null) { + throw e; + } + } + + @Override + public Stream entries() { + List entries = new ArrayList<>(); + try { + /* + * This code should be revisited to avoid buffering of the entries. + * 1) Do we really need sorting classes? This force buffering of entries. + * libs, cmds and configs are not sorted. + * 2) I/O streams should be concatenated instead of buffering into + * entries list. + * 3) Close I/O streams in a close handler. + */ + if (classes != null) { + try (Stream stream = Files.walk(classes)) { + entries.addAll(stream + .filter(p -> !Files.isDirectory(p) + && !classes.relativize(p).toString().startsWith("_the.") + && !classes.relativize(p).toString().equals("javac_state")) + .sorted() + .map(p -> toEntry(p, classes, EntryType.CLASS_OR_RESOURCE)) + .collect(Collectors.toList())); + } + } + if (cmds != null) { + try (Stream stream = Files.walk(cmds)) { + entries.addAll(stream + .filter(p -> !Files.isDirectory(p)) + .map(p -> toEntry(p, cmds, EntryType.NATIVE_CMD)) + .collect(Collectors.toList())); + } + } + if (libs != null) { + try (Stream stream = Files.walk(libs)) { + entries.addAll(stream + .filter(p -> !Files.isDirectory(p)) + .map(p -> toEntry(p, libs, EntryType.NATIVE_LIB)) + .collect(Collectors.toList())); + } + } + if (configs != null) { + try (Stream stream = Files.walk(configs)) { + entries.addAll(stream .filter(p -> !Files.isDirectory(p)) - .map(p -> toEntry(p, cmds, Section.CMDS)) - .forEach(consumer::accept); - if (libs != null) - Files.walk(libs) - .filter(p -> !Files.isDirectory(p)) - .map(p -> toEntry(p, libs, Section.LIBS)) - .forEach(consumer::accept); - if (configs != null) - Files.walk(configs) - .filter(p -> !Files.isDirectory(p)) - .map(p -> toEntry(p, configs, Section.CONFIGS)) - .forEach(consumer::accept); + .map(p -> toEntry(p, configs, EntryType.CONFIG)) + .collect(Collectors.toList())); + } + } } catch (IOException ioe) { throw new UncheckedIOException(ioe); } + return entries.stream(); } - private static class FileEntry implements Entry { - private final String name; - private final InputStream is; + private class FileEntry extends Entry { private final boolean isDirectory; - private final Section section; - FileEntry(String name, InputStream is, - boolean isDirectory, Section section) { - this.name = name; - this.is = is; + private final long size; + private final Path entryPath; + FileEntry(Path entryPath, String path, EntryType type, + boolean isDirectory, long size) { + super(ModuleArchive.this, path, path, type); + this.entryPath = entryPath; this.isDirectory = isDirectory; - this.section = section; - } - public String getName() { - return name; - } - public Section getSection() { - return section; - } - public InputStream getInputStream() { - return is; + this.size = size; } + public boolean isDirectory() { return isDirectory; } + + @Override + public long size() { + return size; + } + + @Override + public InputStream stream() throws IOException { + InputStream stream = Files.newInputStream(entryPath); + opened.add(stream); + return stream; + } } - private Entry toEntry(Path entryPath, Path basePath, Section section) { + private Entry toEntry(Path entryPath, Path basePath, EntryType section) { try { - return new FileEntry(basePath.relativize(entryPath).toString().replace('\\', '/'), - Files.newInputStream(entryPath), false, - section); + String path = basePath.relativize(entryPath).toString().replace('\\', '/'); + return new FileEntry(entryPath, path, section, + false, Files.size(entryPath)); } catch (IOException e) { throw new UncheckedIOException(e); } } - - @Override - public Consumer defaultImageWriter(Path path, OutputStream out) { - return new DefaultEntryWriter(path, out); - } - - private static class DefaultEntryWriter implements Consumer { - private final Path root; - private final OutputStream out; - - DefaultEntryWriter(Path root, OutputStream out) { - this.root = root; - this.out = out; - } - - @Override - public void accept(Archive.Entry entry) { - try { - FileEntry e = (FileEntry)entry; - Section section = e.getSection(); - String filename = e.getName(); - - try (InputStream in = entry.getInputStream()) { - switch (section) { - case CLASSES: - if (!filename.startsWith("_the.") && !filename.equals("javac_state")) - writeEntry(in); - break; - case LIBS: - writeEntry(in, destFile(nativeDir(filename), filename)); - break; - case CMDS: - Path path = destFile("bin", filename); - writeEntry(in, path); - path.toFile().setExecutable(true, false); - break; - case CONFIGS: - writeEntry(in, destFile("conf", filename)); - break; - default: - throw new InternalError("unexpected entry: " + filename); - } - } - } catch (IOException x) { - throw new UncheckedIOException(x); - } - } - - private Path destFile(String dir, String filename) { - return root.resolve(dir).resolve(filename); - } - - private static void writeEntry(InputStream in, Path dstFile) throws IOException { - if (Files.notExists(dstFile.getParent())) - Files.createDirectories(dstFile.getParent()); - Files.copy(in, dstFile); - } - - private void writeEntry(InputStream in) throws IOException { - byte[] buf = new byte[8192]; - int n; - while ((n = in.read(buf)) > 0) - out.write(buf, 0, n); - } - - private static String nativeDir(String filename) { - if (System.getProperty("os.name").startsWith("Windows")) { - if (filename.endsWith(".dll") || filename.endsWith(".diz") - || filename.endsWith(".pdb") || filename.endsWith(".map")) { - return "bin"; - } else { - return "lib"; - } - } else { - return "lib"; - } - } - } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/Archive.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/Archive.java index 2843d18a228..96f5e256681 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/Archive.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/Archive.java @@ -24,42 +24,95 @@ */ package jdk.internal.jimage; +import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Path; -import java.util.function.Consumer; +import java.util.stream.Stream; /** * An Archive of all content, classes, resources, configuration files, and * other, for a module. */ public interface Archive { + + /** + * Entry is contained in an Archive + */ + public abstract class Entry { + + public static enum EntryType { + + MODULE_NAME, + CLASS_OR_RESOURCE, + NATIVE_LIB, + NATIVE_CMD, + CONFIG, + SERVICE; + } + + private final String name; + private final EntryType type; + private final Archive archive; + private final String path; + + public Entry(Archive archive, String path, String name, EntryType type) { + this.archive = archive; + this.path = path; + this.name = name; + this.type = type; + } + + public Archive archive() { + return archive; + } + + public String path() { + return path; + } + + public EntryType type() { + return type; + } + + /** + * Returns the name of this entry. + */ + public String name() { + return name; + } + + @Override + public String toString() { + return "type " + type.name() + " path " + path; + } + + /** + * Returns the number of uncompressed bytes for this entry. + */ + public abstract long size(); + + public abstract InputStream stream() throws IOException; + } + /** * The module name. */ String moduleName(); /** - * Visits all classes and resources. + * Stream of Entry. + * The stream of entries needs to be closed after use + * since it might cover lazy I/O based resources. + * So callers need to use a try-with-resources block. */ - void visitResources(Consumer consumer); + Stream entries(); /** - * Visits all entries in the Archive. + * Open the archive */ - void visitEntries(Consumer consumer) ; + void open() throws IOException; /** - * An entries in the Archive. + * Close the archive */ - interface Entry { - String getName(); - InputStream getInputStream(); - boolean isDirectory(); - } - - /** - * A Consumer suitable for writing Entries from this Archive. - */ - Consumer defaultImageWriter(Path path, OutputStream out); + void close() throws IOException; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java index d09483839c1..1424c4d8d2b 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java @@ -24,63 +24,88 @@ */ package jdk.internal.jimage; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.File; +import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; -import java.nio.MappedByteBuffer; -import java.nio.channels.FileChannel; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.Comparator; +import java.util.stream.IntStream; public class BasicImageReader { private final String imagePath; - private final PReader preader; + private final ImageSubstrate substrate; private final ByteOrder byteOrder; - private final ImageHeader header; - private final int indexSize; - private final IntBuffer redirectBuffer; - private final IntBuffer offsetsBuffer; - private final ByteBuffer locationsBuffer; - private final ByteBuffer stringsBuffer; - private final ImageStrings strings; + private final ImageStringsReader strings; - protected BasicImageReader(String imagePath, ByteOrder byteOrder) throws IOException { + protected BasicImageReader(String imagePath, ByteOrder byteOrder) + throws IOException { this.imagePath = imagePath; - this.preader = PReader.open(imagePath); + this.substrate = openImageSubstrate(imagePath, byteOrder); this.byteOrder = byteOrder; - this.header = ImageHeader.readFrom(byteOrder, getIntBuffer(0, ImageHeader.getHeaderSize())); - this.indexSize = header.getIndexSize(); - this.redirectBuffer = getIntBuffer(header.getRedirectOffset(), header.getRedirectSize()); - this.offsetsBuffer = getIntBuffer(header.getOffsetsOffset(), header.getOffsetsSize()); - this.locationsBuffer = getByteBuffer(header.getLocationsOffset(), header.getLocationsSize()); - this.stringsBuffer = getByteBuffer(header.getStringsOffset(), header.getStringsSize()); - this.strings = new ImageStrings(new ImageStream(stringsBuffer)); + this.strings = new ImageStringsReader(this); } protected BasicImageReader(String imagePath) throws IOException { this(imagePath, ByteOrder.nativeOrder()); } + private static ImageSubstrate openImageSubstrate(String imagePath, ByteOrder byteOrder) + throws IOException { + ImageSubstrate substrate; + + try { + substrate = ImageNativeSubstrate.openImage(imagePath, byteOrder); + } catch (UnsatisfiedLinkError ex) { + substrate = ImageJavaSubstrate.openImage(imagePath, byteOrder); + } + + return substrate; + } + public static BasicImageReader open(String imagePath) throws IOException { return new BasicImageReader(imagePath, ByteOrder.nativeOrder()); } + public static void releaseByteBuffer(ByteBuffer buffer) { + ImageBufferCache.releaseBuffer(buffer); + } + + public ByteOrder getByteOrder() { + return byteOrder; + } + public String imagePath() { return imagePath; } + public String imagePathName() { + int slash = imagePath().lastIndexOf(File.separator); + + if (slash != -1) { + return imagePath().substring(slash + 1); + } + + return imagePath(); + } + public boolean isOpen() { - return preader.isOpen(); + return true; } public void close() throws IOException { - preader.close(); + substrate.close(); } - public ImageHeader getHeader() { - return header; + public ImageHeader getHeader() throws IOException { + return ImageHeader.readFrom( + getIndexIntBuffer(0, ImageHeader.getHeaderSize())); + } + + public ImageStringsReader getStrings() { + return strings; } public ImageLocation findLocation(String name) { @@ -92,148 +117,147 @@ public class BasicImageReader { } public synchronized ImageLocation findLocation(UTF8String name) { - int count = header.getLocationCount(); - int hash = name.hashCode() % count; - int redirect = getRedirect(hash); - - if (redirect == 0) { - return null; - } - - int index; - - if (redirect < 0) { - // If no collision. - index = -redirect - 1; - } else { - // If collision, recompute hash code. - index = name.hashCode(redirect) % count; - } - - int offset = getOffset(index); - - if (offset == 0) { - return null; - } - - ImageLocation location = getLocation(offset); - - return location.verify(name) ? location : null; + return substrate.findLocation(name, strings); } public String[] getEntryNames() { - return getEntryNames(true); - } - - public String[] getEntryNames(boolean sorted) { - int count = header.getLocationCount(); - List list = new ArrayList<>(); - - for (int i = 0; i < count; i++) { - int offset = getOffset(i); - - if (offset != 0) { - ImageLocation location = ImageLocation.readFrom(locationsBuffer, offset, strings); - list.add(location.getFullnameString()); - } - } - - String[] array = list.toArray(new String[0]); - - if (sorted) { - Arrays.sort(array); - } - - return array; + return IntStream.of(substrate.attributeOffsets()) + .filter(o -> o != 0) + .mapToObj(o -> ImageLocation.readFrom(this, o).getFullNameString()) + .sorted() + .toArray(String[]::new); } protected ImageLocation[] getAllLocations(boolean sorted) { - int count = header.getLocationCount(); - List list = new ArrayList<>(); - - for (int i = 0; i < count; i++) { - int offset = getOffset(i); - - if (offset != 0) { - ImageLocation location = ImageLocation.readFrom(locationsBuffer, offset, strings); - list.add(location); - } - } - - ImageLocation[] array = list.toArray(new ImageLocation[0]); - - if (sorted) { - Arrays.sort(array, (ImageLocation loc1, ImageLocation loc2) -> - loc1.getFullnameString().compareTo(loc2.getFullnameString())); - } - - return array; + return IntStream.of(substrate.attributeOffsets()) + .filter(o -> o != 0) + .mapToObj(o -> ImageLocation.readFrom(this, o)) + .sorted(Comparator.comparing(ImageLocation::getFullNameString)) + .toArray(ImageLocation[]::new); } - private IntBuffer getIntBuffer(long offset, long size) throws IOException { - MappedByteBuffer buffer = preader.channel().map(FileChannel.MapMode.READ_ONLY, offset, size); + private IntBuffer getIndexIntBuffer(long offset, long size) + throws IOException { + ByteBuffer buffer = substrate.getIndexBuffer(offset, size); buffer.order(byteOrder); return buffer.asIntBuffer(); } - private ByteBuffer getByteBuffer(long offset, long size) throws IOException { - MappedByteBuffer buffer = preader.channel().map(FileChannel.MapMode.READ_ONLY, offset, size); - // order is not copied into the readonly copy. - ByteBuffer readOnly = buffer.asReadOnlyBuffer(); - readOnly.order(byteOrder); - return readOnly; + ImageLocation getLocation(int offset) { + return ImageLocation.readFrom(this, offset); } - private int getRedirect(int index) { - return redirectBuffer.get(index); - } - - private int getOffset(int index) { - return offsetsBuffer.get(index); - } - - private ImageLocation getLocation(int offset) { - return ImageLocation.readFrom(locationsBuffer, offset, strings); + public long[] getAttributes(int offset) { + return substrate.getAttributes(offset); } public String getString(int offset) { - return strings.get(offset).toString(); + return getUTF8String(offset).toString(); } - public byte[] getResource(ImageLocation loc) throws IOException { + public UTF8String getUTF8String(int offset) { + return new UTF8String(substrate.getStringBytes(offset)); + } + + private byte[] getBufferBytes(ByteBuffer buffer, long size) { + assert size < Integer.MAX_VALUE; + byte[] bytes = new byte[(int)size]; + buffer.get(bytes); + + return bytes; + } + + private byte[] getBufferBytes(long offset, long size) { + ByteBuffer buffer = substrate.getDataBuffer(offset, size); + + return getBufferBytes(buffer, size); + } + + public byte[] getResource(ImageLocation loc) { + long offset = loc.getContentOffset(); long compressedSize = loc.getCompressedSize(); + long uncompressedSize = loc.getUncompressedSize(); assert compressedSize < Integer.MAX_VALUE; + assert uncompressedSize < Integer.MAX_VALUE; - if (compressedSize == 0) { - return preader.read((int)loc.getUncompressedSize(), - indexSize + loc.getContentOffset()); - } else { - byte[] buf = preader.read((int)compressedSize, - indexSize + loc.getContentOffset()); - return ImageFile.Compressor.decompress(buf); + if (substrate.supportsDataBuffer() && compressedSize == 0) { + return getBufferBytes(offset, uncompressedSize); } + + ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize); + boolean isRead; + + if (compressedSize != 0) { + ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize); + isRead = substrate.read(offset, compressedBuffer, compressedSize, + uncompressedBuffer, uncompressedSize); + ImageBufferCache.releaseBuffer(compressedBuffer); + } else { + isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize); + } + + byte[] bytes = isRead ? getBufferBytes(uncompressedBuffer, + uncompressedSize) : null; + + ImageBufferCache.releaseBuffer(uncompressedBuffer); + + return bytes; } - public byte[] getResource(String name) throws IOException { + public byte[] getResource(String name) { ImageLocation location = findLocation(name); return location != null ? getResource(location) : null; } - public List getNames(String name) throws IOException { - return getNames(getResource(name)); - } + public ByteBuffer getResourceBuffer(ImageLocation loc) { + long offset = loc.getContentOffset(); + long compressedSize = loc.getCompressedSize(); + long uncompressedSize = loc.getUncompressedSize(); + assert compressedSize < Integer.MAX_VALUE; + assert uncompressedSize < Integer.MAX_VALUE; - public List getNames(byte[] bytes) { - IntBuffer buffer = ByteBuffer.wrap(bytes).asIntBuffer(); - List names = new ArrayList<>(); - - while (buffer.hasRemaining()) { - int offset = buffer.get(); - names.add(getString(offset)); + if (substrate.supportsDataBuffer() && compressedSize == 0) { + return substrate.getDataBuffer(offset, uncompressedSize); } - return names; + ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize); + boolean isRead; + + if (compressedSize != 0) { + ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize); + isRead = substrate.read(offset, compressedBuffer, compressedSize, + uncompressedBuffer, uncompressedSize); + ImageBufferCache.releaseBuffer(compressedBuffer); + } else { + isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize); + } + + if (isRead) { + return uncompressedBuffer; + } else { + ImageBufferCache.releaseBuffer(uncompressedBuffer); + + return null; + } + } + + public ByteBuffer getResourceBuffer(String name) { + ImageLocation location = findLocation(name); + + return location != null ? getResourceBuffer(location) : null; + } + + public InputStream getResourceStream(ImageLocation loc) { + byte[] bytes = getResource(loc); + + return new ByteArrayInputStream(bytes); + } + + public InputStream getResourceStream(String name) { + ImageLocation location = findLocation(name); + + return location != null ? getResourceStream(location) : null; } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageWriter.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageWriter.java index b97cb40cd2f..b2d1b682fbf 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageWriter.java @@ -25,67 +25,30 @@ package jdk.internal.jimage; -import java.io.PrintStream; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; public final class BasicImageWriter { + + public static final String IMAGE_EXT = ".jimage"; + public static final String BOOT_NAME = "bootmodules"; + public static final String BOOT_IMAGE_NAME = BOOT_NAME + IMAGE_EXT; + private final static int RETRY_LIMIT = 1000; private ByteOrder byteOrder; - private ImageStrings strings; - private int count; + private ImageStringsWriter strings; + private int length; private int[] redirect; - private ImageLocation[] locations; - private List input; + private ImageLocationWriter[] locations; + private List input; private ImageStream headerStream; private ImageStream redirectStream; private ImageStream locationOffsetStream; private ImageStream locationStream; private ImageStream allIndexStream; - static class ImageBucket implements Comparable { - final List list; - - ImageBucket() { - this.list = new ArrayList<>(); - } - - void add(ImageLocation location) { - list.add(location); - } - - int getSize() { - return list.size(); - } - - List getList() { - return list; - } - - ImageLocation getFirst() { - assert !list.isEmpty() : "bucket should never be empty"; - return list.get(0); - } - - @Override - public int hashCode() { - return getFirst().hashCode(); - } - - @Override - public boolean equals(Object obj) { - return this == obj; - } - - @Override - public int compareTo(ImageBucket o) { - return o.getSize() - getSize(); - } - } - public BasicImageWriter() { this(ByteOrder.nativeOrder()); } @@ -93,7 +56,7 @@ public final class BasicImageWriter { public BasicImageWriter(ByteOrder byteOrder) { this.byteOrder = byteOrder; this.input = new ArrayList<>(); - this.strings = new ImageStrings(); + this.strings = new ImageStringsWriter(); this.headerStream = new ImageStream(byteOrder); this.redirectStream = new ImageStream(byteOrder); this.locationOffsetStream = new ImageStream(byteOrder); @@ -101,6 +64,10 @@ public final class BasicImageWriter { this.allIndexStream = new ImageStream(byteOrder); } + public ByteOrder getByteOrder() { + return byteOrder; + } + public int addString(String string) { return addString(new UTF8String(string)); } @@ -109,104 +76,48 @@ public final class BasicImageWriter { return strings.add(string); } - public void addLocation(String fullname, long contentOffset, long compressedSize, long uncompressedSize) { - ImageLocation location = ImageLocation.newLocation(new UTF8String(fullname), strings, contentOffset, compressedSize, uncompressedSize); + public String getString(int offset) { + UTF8String utf8 = strings.get(offset); + return utf8 != null? utf8.toString() : null; + } + + public void addLocation(String fullname, long contentOffset, + long compressedSize, long uncompressedSize) { + ImageLocationWriter location = + ImageLocationWriter.newLocation(new UTF8String(fullname), strings, + contentOffset, compressedSize, uncompressedSize); input.add(location); - count++; + length++; + } + + ImageLocationWriter[] getLocations() { + return locations; + } + + int getLocationsCount() { + return input.size(); } private void generatePerfectHash() { - redo: - while(true) { - redirect = new int[count]; - locations = new ImageLocation[count]; + PerfectHashBuilder builder = + new PerfectHashBuilder<>( + new PerfectHashBuilder.Entry().getClass(), + new PerfectHashBuilder.Bucket().getClass()); - ImageBucket[] sorted = createBuckets(); - - int free = 0; - - for (ImageBucket bucket : sorted) { - if (bucket.getSize() != 1) { - if (!packCollidedEntries(bucket, count)) { - count = (count + 1) | 1; - - continue redo; - } - } else { - for ( ; free < count && locations[free] != null; free++) {} - assert free < count : "no free slots"; - locations[free] = bucket.getFirst(); - redirect[bucket.hashCode() % count] = -1 - free; - free++; - } - } - - break; - } - } - - private ImageBucket[] createBuckets() { - ImageBucket[] buckets = new ImageBucket[count]; - - input.stream().forEach((location) -> { - int index = location.hashCode() % count; - ImageBucket bucket = buckets[index]; - - if (bucket == null) { - buckets[index] = bucket = new ImageBucket(); - } - - bucket.add(location); + input.forEach((location) -> { + builder.put(location.getFullName(), location); }); - ImageBucket[] sorted = Arrays.asList(buckets).stream() - .filter((bucket) -> (bucket != null)) - .sorted() - .toArray(ImageBucket[]::new); + builder.generate(); - return sorted; - } + length = builder.getCount(); + redirect = builder.getRedirect(); + PerfectHashBuilder.Entry[] order = builder.getOrder(); + locations = new ImageLocationWriter[length]; - private boolean packCollidedEntries(ImageBucket bucket, int count) { - List undo = new ArrayList<>(); - int base = UTF8String.HASH_MULTIPLIER + 1; - - int retry = 0; - - redo: - while (true) { - for (ImageLocation location : bucket.getList()) { - int index = location.hashCode(base) % count; - - if (locations[index] != null) { - undo.stream().forEach((i) -> { - locations[i] = null; - }); - - undo.clear(); - base++; - - if (base == 0) { - base = 1; - } - - if (++retry > RETRY_LIMIT) { - return false; - } - - continue redo; - } - - locations[index] = location; - undo.add(index); - } - - redirect[bucket.hashCode() % count] = base; - - break; + for (int i = 0; i < length; i++) { + locations[i] = order[i].getValue(); } - - return true; } private void prepareStringBytes() { @@ -214,17 +125,17 @@ public final class BasicImageWriter { } private void prepareRedirectBytes() { - for (int i = 0; i < count; i++) { + for (int i = 0; i < length; i++) { redirectStream.putInt(redirect[i]); } } private void prepareLocationBytes() { // Reserve location offset zero for empty locations - locationStream.put(ImageLocation.ATTRIBUTE_END << 3); + locationStream.put(ImageLocationWriter.ATTRIBUTE_END << 3); - for (int i = 0; i < count; i++) { - ImageLocation location = locations[i]; + for (int i = 0; i < length; i++) { + ImageLocationWriter location = locations[i]; if (location != null) { location.writeTo(locationStream); @@ -235,14 +146,16 @@ public final class BasicImageWriter { } private void prepareOffsetBytes() { - for (int i = 0; i < count; i++) { - ImageLocation location = locations[i]; - locationOffsetStream.putInt(location != null ? location.getLocationOffset() : 0); + for (int i = 0; i < length; i++) { + ImageLocationWriter location = locations[i]; + int offset = location != null ? location.getLocationOffset() : 0; + locationOffsetStream.putInt(offset); } } private void prepareHeaderBytes() { - ImageHeader header = new ImageHeader(count, locationStream.getSize(), strings.getSize()); + ImageHeader header = new ImageHeader(input.size(), length, + locationStream.getSize(), strings.getSize()); header.writeTo(headerStream); } @@ -268,33 +181,15 @@ public final class BasicImageWriter { return allIndexStream.toArray(); } - ImageLocation find(UTF8String key) { - int index = key.hashCode() % count; - index = redirect[index]; + ImageLocationWriter find(UTF8String key) { + int index = redirect[key.hashCode() % length]; if (index < 0) { index = -index - 1; - ImageLocation location = locations[index]; - - return location; } else { - index = key.hashCode(index) % count; - ImageLocation location = locations[index]; - - return location; + index = key.hashCode(index) % length; } - } - public void statistics() { - getBytes(); - PrintStream out = System.out; - out.println("Count: " + count); - out.println("Header bytes size: " + headerStream.getSize()); - out.println("Redirect bytes size: " + redirectStream.getSize()); - out.println("Offset bytes size: " + locationOffsetStream.getSize()); - out.println("Location bytes size: " + locationStream.getSize()); - out.println("String count: " + strings.getCount()); - out.println("String bytes size: " + strings.getSize()); - out.println("Total bytes size: " + allIndexStream.getSize()); + return locations[index]; } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ExternalFilesWriter.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ExternalFilesWriter.java new file mode 100644 index 00000000000..df414a6b6cf --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ExternalFilesWriter.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.function.Consumer; +import jdk.internal.jimage.Archive.Entry; + +/** + * A Consumer suitable for processing non resources Archive Entry and writing it to the + * appropriate location. + */ +class ExternalFilesWriter implements Consumer { + private final Path root; + + ExternalFilesWriter(Path root) { + this.root = root; + } + + @Override + public void accept(Entry entry) { + String name = entry.path(); + try { + String filename = entry.path(); + try (InputStream in = entry.stream()) { + switch (entry.type()) { + case NATIVE_LIB: + writeEntry(in, destFile(nativeDir(filename), filename)); + break; + case NATIVE_CMD: + Path path = destFile("bin", filename); + writeEntry(in, path); + path.toFile().setExecutable(true); + break; + case CONFIG: + writeEntry(in, destFile("conf", filename)); + break; + case MODULE_NAME: + // skip + break; + case SERVICE: + //throw new UnsupportedOperationException(name + " in " + zipfile.toString()); //TODO + throw new UnsupportedOperationException(name + " in " + name); + default: + //throw new InternalError("unexpected entry: " + name + " " + zipfile.toString()); //TODO + throw new InternalError("unexpected entry: " + name + " " + name); + } + } + } catch (FileAlreadyExistsException x) { + System.err.println("File already exists (skipped) " + name); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + } + + private Path destFile(String dir, String filename) { + return root.resolve(dir).resolve(filename); + } + + private void writeEntry(InputStream in, Path dstFile) throws IOException { + Files.createDirectories(dstFile.getParent()); + Files.copy(in, dstFile); + } + + private static String nativeDir(String filename) { + if (System.getProperty("os.name").startsWith("Windows")) { + if (filename.endsWith(".dll") || filename.endsWith(".diz") + || filename.endsWith(".pdb") || filename.endsWith(".map")) { + return "bin"; + } else { + return "lib"; + } + } else { + return "lib"; + } + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageBufferCache.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageBufferCache.java new file mode 100644 index 00000000000..6929f74e21d --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageBufferCache.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.nio.ByteBuffer; +import java.util.ArrayList; + +class ImageBufferCache { + private static final int MAX_FREE_BUFFERS = 3; + private static final int LARGE_BUFFER = 0x10000; + private static final ThreadLocal> + threadLocal = new ThreadLocal<>(); + + private final ByteBuffer buffer; + private boolean isUsed; + + static ByteBuffer getBuffer(long size) { + assert size < Integer.MAX_VALUE; + ByteBuffer buffer = null; + + if (size > LARGE_BUFFER) { + buffer = ByteBuffer.allocateDirect((int)((size + 0xFFF) & ~0xFFF)); + } else { + ArrayList buffers = threadLocal.get(); + + if (buffers == null) { + buffers = new ArrayList<>(MAX_FREE_BUFFERS); + threadLocal.set(buffers); + } + + int i = 0, j = buffers.size(); + for (ImageBufferCache imageBuffer : buffers) { + if (size <= imageBuffer.capacity()) { + j = i; + + if (!imageBuffer.isUsed) { + imageBuffer.isUsed = true; + buffer = imageBuffer.buffer; + + break; + } + } else { + break; + } + + i++; + } + + if (buffer == null) { + ImageBufferCache imageBuffer = new ImageBufferCache((int)size); + buffers.add(j, imageBuffer); + buffer = imageBuffer.buffer; + } + } + + buffer.rewind(); + buffer.limit((int)size); + + return buffer; + } + + static void releaseBuffer(ByteBuffer buffer) { + ArrayList buffers = threadLocal.get(); + + if (buffers == null ) { + return; + } + + if (buffer.capacity() > LARGE_BUFFER) { + return; + } + + int i = 0, j = buffers.size(); + for (ImageBufferCache imageBuffer : buffers) { + if (!imageBuffer.isUsed) { + j = Math.min(j, i); + } + + if (imageBuffer.buffer == buffer) { + imageBuffer.isUsed = false; + j = Math.min(j, i); + + break; + } + } + + if (buffers.size() > MAX_FREE_BUFFERS && j != buffers.size()) { + buffers.remove(j); + } + } + + private ImageBufferCache(int needed) { + this.buffer = ByteBuffer.allocateDirect((needed + 0xFFF) & ~0xFFF); + this.isUsed = true; + this.buffer.limit(needed); + } + + private long capacity() { + return buffer.capacity(); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageFile.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageFile.java deleted file mode 100644 index 6930ab80736..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageFile.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * 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.jimage; - -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteOrder; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.zip.DataFormatException; -import java.util.zip.Deflater; -import java.util.zip.Inflater; -import jdk.internal.jimage.ImageModules.Loader; -import jdk.internal.jimage.ImageModules.ModuleIndex; - -/** - * An image (native endian.) - *
{@code
- * {
- *   u4 magic;
- *   u2 major_version;
- *   u2 minor_version;
- *   u4 location_count;
- *   u4 location_attributes_size;
- *   u4 strings_size;
- *   u4 redirect[location_count];
- *   u4 offsets[location_count];
- *   u1 location_attributes[location_attributes_size];
- *   u1 strings[strings_size];
- *   u1 content[if !EOF];
- * }
- * }
- */ -public final class ImageFile { - private static final String JAVA_BASE = "java.base"; - private static final String IMAGE_EXT = ".jimage"; - private static final String JAR_EXT = ".jar"; - private final Path root; - private final Path mdir; - private final Map> resourcesForModule = new HashMap<>(); - - private ImageFile(Path path) { - this.root = path; - this.mdir = root.resolve(path.getFileSystem().getPath("lib", "modules")); - } - - public static ImageFile open(Path path) throws IOException { - ImageFile lib = new ImageFile(path); - return lib.open(); - } - - private ImageFile open() throws IOException { - Path path = mdir.resolve("bootmodules" + IMAGE_EXT); - - ImageReader reader = new ImageReader(path.toString()); - ImageHeader header = reader.getHeader(); - - if (header.getMagic() != ImageHeader.MAGIC) { - if (header.getMagic() == ImageHeader.BADMAGIC) { - throw new IOException(path + ": Image may be not be native endian"); - } else { - throw new IOException(path + ": Invalid magic number"); - } - } - - if (header.getMajorVersion() > ImageHeader.MAJOR_VERSION || - (header.getMajorVersion() == ImageHeader.MAJOR_VERSION && - header.getMinorVersion() > ImageHeader.MINOR_VERSION)) { - throw new IOException("invalid version number"); - } - - return this; - } - - public static ImageFile create(Path output, - Set archives, - ImageModules modules) - throws IOException - { - return ImageFile.create(output, archives, modules, ByteOrder.nativeOrder()); - } - - public static ImageFile create(Path output, - Set archives, - ImageModules modules, - ByteOrder byteOrder) - throws IOException - { - ImageFile lib = new ImageFile(output); - // get all resources - lib.readModuleEntries(modules, archives); - // write to modular image - lib.writeImage(modules, archives, byteOrder); - return lib; - } - - private void writeImage(ImageModules modules, - Set archives, - ByteOrder byteOrder) - throws IOException - { - // name to Archive file - Map nameToArchive = - archives.stream() - .collect(Collectors.toMap(Archive::moduleName, Function.identity())); - - Files.createDirectories(mdir); - for (Loader l : Loader.values()) { - Set mods = modules.getModules(l); - - try (OutputStream fos = Files.newOutputStream(mdir.resolve(l.getName() + IMAGE_EXT)); - BufferedOutputStream bos = new BufferedOutputStream(fos); - DataOutputStream out = new DataOutputStream(bos)) { - // store index in addition of the class loader map for boot loader - BasicImageWriter writer = new BasicImageWriter(byteOrder); - Set duplicates = new HashSet<>(); - - // build package map for modules and add as resources - ModuleIndex mindex = modules.buildModuleIndex(l, writer); - long offset = mindex.size(); - - // the order of traversing the resources and the order of - // the module content being written must be the same - for (String mn : mods) { - for (Resource res : resourcesForModule.get(mn)) { - String path = res.name(); - long uncompressedSize = res.size(); - long compressedSize = res.csize(); - long onFileSize = compressedSize != 0 ? compressedSize : uncompressedSize; - - if (duplicates.contains(path)) { - System.err.format("duplicate resource \"%s\", skipping%n", path); - // TODO Need to hang bytes on resource and write from resource not zip. - // Skipping resource throws off writing from zip. - offset += onFileSize; - continue; - } - duplicates.add(path); - writer.addLocation(path, offset, compressedSize, uncompressedSize); - offset += onFileSize; - } - } - - // write header and indices - byte[] bytes = writer.getBytes(); - out.write(bytes, 0, bytes.length); - - // write module table and packages - mindex.writeTo(out); - - // write module content - for (String mn : mods) { - writeModule(nameToArchive.get(mn), out); - } - } - } - } - - private void readModuleEntries(ImageModules modules, - Set archives) - throws IOException - { - for (Archive archive : archives) { - List res = new ArrayList<>(); - archive.visitResources(x-> res.add(x)); - - String mn = archive.moduleName(); - resourcesForModule.put(mn, res); - - Set pkgs = res.stream().map(Resource::name) - .filter(n -> n.endsWith(".class")) - .map(this::toPackage) - .distinct() - .collect(Collectors.toSet()); - modules.setPackages(mn, pkgs); - } - } - - private String toPackage(String name) { - int index = name.lastIndexOf('/'); - if (index > 0) { - return name.substring(0, index).replace('/', '.'); - } else { - // ## unnamed package - System.err.format("Warning: %s in unnamed package%n", name); - return ""; - } - } - - private void writeModule(Archive archive, - OutputStream out) - throws IOException - { - Consumer consumer = archive.defaultImageWriter(root, out); - archive.visitEntries(consumer); - } - - - static class Compressor { - public static byte[] compress(byte[] bytesIn) { - Deflater deflater = new Deflater(); - deflater.setInput(bytesIn); - ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length); - byte[] buffer = new byte[1024]; - - deflater.finish(); - while (!deflater.finished()) { - int count = deflater.deflate(buffer); - stream.write(buffer, 0, count); - } - - try { - stream.close(); - } catch (IOException ex) { - return bytesIn; - } - - byte[] bytesOut = stream.toByteArray(); - deflater.end(); - - return bytesOut; - } - - public static byte[] decompress(byte[] bytesIn) { - Inflater inflater = new Inflater(); - inflater.setInput(bytesIn); - ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length); - byte[] buffer = new byte[1024]; - - while (!inflater.finished()) { - int count; - - try { - count = inflater.inflate(buffer); - } catch (DataFormatException ex) { - return null; - } - - stream.write(buffer, 0, count); - } - - try { - stream.close(); - } catch (IOException ex) { - return null; - } - - byte[] bytesOut = stream.toByteArray(); - inflater.end(); - - return bytesOut; - } - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageFileCreator.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageFileCreator.java new file mode 100644 index 00000000000..1a16ad1c69f --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageFileCreator.java @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.internal.jimage.Archive.Entry; +import jdk.internal.jimage.Archive.Entry.EntryType; +import static jdk.internal.jimage.BasicImageWriter.BOOT_NAME; +import static jdk.internal.jimage.BasicImageWriter.IMAGE_EXT; + +/** + * An image (native endian.) + *
{@code
+ * {
+ *   u4 magic;
+ *   u2 major_version;
+ *   u2 minor_version;
+ *   u4 resource_count;
+ *   u4 table_length;
+ *   u4 location_attributes_size;
+ *   u4 strings_size;
+ *   u4 redirect[table_length];
+ *   u4 offsets[table_length];
+ *   u1 location_attributes[location_attributes_size];
+ *   u1 strings[strings_size];
+ *   u1 content[if !EOF];
+ * }
+ * }
+ */ +public final class ImageFileCreator { + private final Path root; + private final Path mdir; + private final Map> entriesForModule = new HashMap<>(); + private ImageFileCreator(Path path) { + this.root = path; + this.mdir = root.resolve(path.getFileSystem().getPath("lib", "modules")); + } + + public static ImageFileCreator create(Path output, + Set archives) + throws IOException { + return create(output, BOOT_NAME, archives, ByteOrder.nativeOrder()); + } + + public static ImageFileCreator create(Path output, + Set archives, + ByteOrder byteOrder) + throws IOException { + return create(output, BOOT_NAME, archives, byteOrder); + } + + public static ImageFileCreator create(Path output, + String fileName, + Set archives, + ByteOrder byteOrder) + throws IOException + { + ImageFileCreator image = new ImageFileCreator(output); + // get all entries + Map> modulePackagesMap = new HashMap<>(); + image.readAllEntries(modulePackagesMap, archives); + // write to modular image + image.writeImage(fileName, modulePackagesMap, archives, byteOrder); + return image; + } + + private void readAllEntries(Map> modulePackagesMap, + Set archives) { + archives.stream().forEach((archive) -> { + Map> es; + try(Stream entries = archive.entries()) { + es = entries.collect(Collectors.partitioningBy(n -> n.type() + == EntryType.CLASS_OR_RESOURCE)); + } + String mn = archive.moduleName(); + List all = new ArrayList<>(); + all.addAll(es.get(false)); + all.addAll(es.get(true)); + entriesForModule.put(mn, all); + // Extract package names + Set pkgs = es.get(true).stream().map(Entry::name) + .filter(n -> isClassPackage(n)) + .map(ImageFileCreator::toPackage) + .collect(Collectors.toSet()); + modulePackagesMap.put(mn, pkgs); + }); + } + + public static boolean isClassPackage(String path) { + return path.endsWith(".class"); + } + + public static boolean isResourcePackage(String path) { + path = path.substring(1); + path = path.substring(path.indexOf("/")+1); + return !path.startsWith("META-INF/"); + } + + public static void recreateJimage(Path jimageFile, + Set archives, + Map> modulePackages) + throws IOException { + Map> entriesForModule + = archives.stream().collect(Collectors.toMap( + Archive::moduleName, + a -> { + try(Stream entries = a.entries()) { + return entries.collect(Collectors.toList()); + } + })); + Map nameToArchive + = archives.stream() + .collect(Collectors.toMap(Archive::moduleName, Function.identity())); + ByteOrder order = ByteOrder.nativeOrder(); + ResourcePoolImpl resources = createResources(modulePackages, nameToArchive, + (Entry t) -> { + throw new UnsupportedOperationException("Not supported, no external file " + + "in a jimage file"); + }, entriesForModule, order); + String fileName = jimageFile.getRoot().toString(); + generateJImage(jimageFile, fileName, resources, order); + } + + private void writeImage(String fileName, + Map> modulePackagesMap, + Set archives, + ByteOrder byteOrder) + throws IOException { + Files.createDirectories(mdir); + ExternalFilesWriter filesWriter = new ExternalFilesWriter(root); + // name to Archive file + Map nameToArchive + = archives.stream() + .collect(Collectors.toMap(Archive::moduleName, Function.identity())); + ResourcePoolImpl resources = createResources(modulePackagesMap, + nameToArchive, filesWriter, + entriesForModule, byteOrder); + generateJImage(mdir.resolve(fileName + IMAGE_EXT), fileName, resources, + byteOrder); + } + + private static void generateJImage(Path img, + String fileName, + ResourcePoolImpl resources, + ByteOrder byteOrder + ) throws IOException { + BasicImageWriter writer = new BasicImageWriter(byteOrder); + + Map> modulePackagesMap = resources.getModulePackages(); + + try (OutputStream fos = Files.newOutputStream(img); + BufferedOutputStream bos = new BufferedOutputStream(fos); + DataOutputStream out = new DataOutputStream(bos)) { + Set duplicates = new HashSet<>(); + ImageModuleDataWriter moduleData = + ImageModuleDataWriter.buildModuleData(writer, modulePackagesMap); + moduleData.addLocation(fileName, writer); + long offset = moduleData.size(); + + List content = new ArrayList<>(); + List paths = new ArrayList<>(); + // the order of traversing the resources and the order of + // the module content being written must be the same + for (ResourcePool.Resource res : resources.getResources()) { + String path = res.getPath(); + int index = path.indexOf("/META-INF/"); + if (index != -1) { + path = path.substring(index + 1); + } + + content.add(res); + long uncompressedSize = res.getLength(); + long compressedSize = 0; + if (res instanceof ResourcePool.CompressedResource) { + ResourcePool.CompressedResource comp = + (ResourcePool.CompressedResource) res; + compressedSize = res.getLength(); + uncompressedSize = comp.getUncompressedSize(); + } + long onFileSize = res.getLength(); + + if (duplicates.contains(path)) { + System.err.format("duplicate resource \"%s\", skipping%n", + path); + // TODO Need to hang bytes on resource and write + // from resource not zip. + // Skipping resource throws off writing from zip. + offset += onFileSize; + continue; + } + duplicates.add(path); + writer.addLocation(path, offset, compressedSize, uncompressedSize); + paths.add(path); + offset += onFileSize; + } + + ImageResourcesTree tree = new ImageResourcesTree(offset, writer, paths); + + // write header and indices + byte[] bytes = writer.getBytes(); + out.write(bytes, 0, bytes.length); + + // write module meta data + moduleData.writeTo(out); + + // write module content + for(ResourcePool.Resource res : content) { + byte[] buf = res.getByteArray(); + out.write(buf, 0, buf.length); + } + + tree.addContent(out); + } + } + + private static ResourcePoolImpl createResources(Map> modulePackagesMap, + Map nameToArchive, + Consumer externalFileHandler, + Map> entriesForModule, + ByteOrder byteOrder) throws IOException { + ResourcePoolImpl resources = new ResourcePoolImpl(byteOrder); + Set mods = modulePackagesMap.keySet(); + for (String mn : mods) { + for (Entry entry : entriesForModule.get(mn)) { + String path = entry.name(); + if (entry.type() == EntryType.CLASS_OR_RESOURCE) { + if (!entry.path().endsWith(BOOT_NAME)) { + try (InputStream stream = entry.stream()) { + byte[] bytes = readAllBytes(stream); + path = "/" + mn + "/" + path; + try { + resources.addResource(new ResourcePool.Resource(path, + ByteBuffer.wrap(bytes))); + } catch (Exception ex) { + throw new IOException(ex); + } + } + } + } else { + externalFileHandler.accept(entry); + } + } + // Done with this archive, close it. + Archive archive = nameToArchive.get(mn); + archive.close(); + } + return resources; + } + + private static final int BUF_SIZE = 8192; + + private static byte[] readAllBytes(InputStream is) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buf = new byte[BUF_SIZE]; + while (true) { + int n = is.read(buf); + if (n < 0) { + break; + } + baos.write(buf, 0, n); + } + return baos.toByteArray(); + } + + /** + * Helper method that splits a Resource path onto 3 items: module, parent + * and resource name. + * + * @param path + * @return An array containing module, parent and name. + */ + public static String[] splitPath(String path) { + Objects.requireNonNull(path); + String noRoot = path.substring(1); + int pkgStart = noRoot.indexOf("/"); + String module = noRoot.substring(0, pkgStart); + List result = new ArrayList<>(); + result.add(module); + String pkg = noRoot.substring(pkgStart + 1); + String resName; + int pkgEnd = pkg.lastIndexOf("/"); + if (pkgEnd == -1) { // No package. + resName = pkg; + } else { + resName = pkg.substring(pkgEnd + 1); + } + + pkg = toPackage(pkg, false); + result.add(pkg); + result.add(resName); + + String[] array = new String[result.size()]; + return result.toArray(array); + } + + private static String toPackage(String name) { + String pkg = toPackage(name, true); + return pkg; + } + + private static String toPackage(String name, boolean log) { + int index = name.lastIndexOf('/'); + if (index > 0) { + return name.substring(0, index).replace('/', '.'); + } else { + // ## unnamed package + if (log) { + System.err.format("Warning: %s in unnamed package%n", name); + } + return ""; + } + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java index 25ffa046cf7..f55ef349d92 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java @@ -25,67 +25,76 @@ package jdk.internal.jimage; -import java.nio.ByteOrder; +import java.nio.ByteBuffer; import java.nio.IntBuffer; public final class ImageHeader { public static final int MAGIC = 0xCAFEDADA; public static final int BADMAGIC = 0xDADAFECA; - public static final short MAJOR_VERSION = 0; - public static final short MINOR_VERSION = 1; + public static final int MAJOR_VERSION = 1; + public static final int MINOR_VERSION = 0; private final int magic; - private final short majorVersion; - private final short minorVersion; - private final int locationCount; + private final int majorVersion; + private final int minorVersion; + private final int flags; + private final int resourceCount; + private final int tableLength; private final int locationsSize; private final int stringsSize; - ImageHeader(int locationCount, int locationsSize, int stringsSize) { - this(MAGIC, MAJOR_VERSION, MINOR_VERSION, locationCount, locationsSize, stringsSize); + public ImageHeader(int resourceCount, int tableCount, + int locationsSize, int stringsSize) { + this(MAGIC, MAJOR_VERSION, MINOR_VERSION, 0, resourceCount, + tableCount, locationsSize, stringsSize); } - ImageHeader(int magic, short majorVersion, short minorVersion, int locationCount, - int locationsSize, int stringsSize) + public ImageHeader(int magic, int majorVersion, int minorVersion, + int flags, int resourceCount, + int tableLength, int locationsSize, int stringsSize) { this.magic = magic; this.majorVersion = majorVersion; this.minorVersion = minorVersion; - this.locationCount = locationCount; + this.flags = flags; + this.resourceCount = resourceCount; + this.tableLength = tableLength; this.locationsSize = locationsSize; this.stringsSize = stringsSize; } - static int getHeaderSize() { - return 4 + - 2 + 2 + - 4 + - 4 + - 4; + public static int getHeaderSize() { + return 7 * 4; } - static ImageHeader readFrom(ByteOrder byteOrder, IntBuffer buffer) { + static ImageHeader readFrom(IntBuffer buffer) { int magic = buffer.get(0); int version = buffer.get(1); - short majorVersion = (short)(byteOrder == ByteOrder.BIG_ENDIAN ? - version >>> 16 : (version & 0xFFFF)); - short minorVersion = (short)(byteOrder == ByteOrder.BIG_ENDIAN ? - (version & 0xFFFF) : version >>> 16); - int locationCount = buffer.get(2); - int locationsSize = buffer.get(3); - int stringsSize = buffer.get(4); + int majorVersion = version >>> 16; + int minorVersion = version & 0xFFFF; + int flags = buffer.get(2); + int resourceCount = buffer.get(3); + int tableLength = buffer.get(4); + int locationsSize = buffer.get(5); + int stringsSize = buffer.get(6); - return new ImageHeader(magic, majorVersion, minorVersion, locationCount, - locationsSize, stringsSize); + return new ImageHeader(magic, majorVersion, minorVersion, flags, + resourceCount, tableLength, locationsSize, stringsSize); } void writeTo(ImageStream stream) { - stream.putInt(magic); - stream.putShort(majorVersion); - stream.putShort(minorVersion); - stream.putInt(locationCount); - stream.putInt(locationsSize); - stream.putInt(stringsSize); + stream.ensure(getHeaderSize()); + writeTo(stream.getBuffer()); + } + + public void writeTo(ByteBuffer buffer) { + buffer.putInt(magic); + buffer.putInt(majorVersion << 16 | minorVersion); + buffer.putInt(flags); + buffer.putInt(resourceCount); + buffer.putInt(tableLength); + buffer.putInt(locationsSize); + buffer.putInt(stringsSize); } public int getMagic() { @@ -100,16 +109,24 @@ public final class ImageHeader { return minorVersion; } - public int getLocationCount() { - return locationCount; + public int getFlags() { + return flags; + } + + public int getResourceCount() { + return resourceCount; + } + + public int getTableLength() { + return tableLength; } public int getRedirectSize() { - return locationCount* 4; + return tableLength * 4; } public int getOffsetsSize() { - return locationCount* 4; + return tableLength * 4; } public int getLocationsSize() { diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageJavaSubstrate.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageJavaSubstrate.java new file mode 100644 index 00000000000..96a7f23d216 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageJavaSubstrate.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Paths; +import static java.nio.file.StandardOpenOption.READ; +import jdk.internal.jimage.decompressor.Decompressor; + +final class ImageJavaSubstrate implements ImageSubstrate { + + private final String imagePath; + private final ByteOrder byteOrder; + private final FileChannel channel; + private final ImageHeader header; + private final long indexSize; + private final int[] redirect; + private final int[] offsets; + private final byte[] locations; + private final byte[] strings; + + private final Decompressor decompressor = new Decompressor(); + + private ImageJavaSubstrate(String imagePath, ByteOrder byteOrder) + throws IOException { + this.imagePath = imagePath; + this.byteOrder = byteOrder; + channel = FileChannel.open(Paths.get(imagePath), READ); + + int headerSize = ImageHeader.getHeaderSize(); + ByteBuffer buffer = getIndexBuffer(0, headerSize); + header = ImageHeader.readFrom(buffer.asIntBuffer()); + + if (header.getMagic() != ImageHeader.MAGIC || + header.getMajorVersion() != ImageHeader.MAJOR_VERSION || + header.getMinorVersion() != ImageHeader.MINOR_VERSION) { + throw new IOException("Image not found \"" + imagePath + "\""); + } + + indexSize = header.getIndexSize(); + + redirect = readIntegers(header.getRedirectOffset(), + header.getRedirectSize()); + offsets = readIntegers(header.getOffsetsOffset(), + header.getOffsetsSize()); + locations = readBytes(header.getLocationsOffset(), + header.getLocationsSize()); + strings = readBytes(header.getStringsOffset(), + header.getStringsSize()); + } + + static ImageSubstrate openImage(String imagePath, ByteOrder byteOrder) + throws IOException { + return new ImageJavaSubstrate(imagePath, byteOrder); + } + + @Override + public void close() { + try { + channel.close(); + } catch (IOException ex) { + // Mostly harmless + } + } + + @Override + public boolean supportsDataBuffer() { + return false; + } + + private int[] readIntegers(long offset, long size) { + assert size < Integer.MAX_VALUE; + IntBuffer buffer = readBuffer(offset, size).asIntBuffer(); + int[] integers = new int[(int)size / 4]; + buffer.get(integers); + + return integers; + } + + private byte[] readBytes(long offset, long size) { + assert size < Integer.MAX_VALUE; + ByteBuffer buffer = readBuffer(offset, size); + byte[] bytes = new byte[(int)size]; + buffer.get(bytes); + + return bytes; + } + + private ByteBuffer readBuffer(long offset, long size) { + assert size < Integer.MAX_VALUE; + ByteBuffer buffer = ByteBuffer.allocate((int)size); + buffer.order(byteOrder); + + if (!readBuffer(buffer, offset, size)) { + return null; + } + + return buffer; + } + + private boolean readBuffer(ByteBuffer buffer, long offset, long size) { + assert size < Integer.MAX_VALUE; + assert buffer.limit() == size; + int read = 0; + + try { + read = channel.read(buffer, offset); + buffer.rewind(); + } catch (IOException ex) { + // fall thru + } + + return read == size; + } + + @Override + public ByteBuffer getIndexBuffer(long offset, long size) { + assert size < Integer.MAX_VALUE; + return readBuffer(offset, size); + } + + @Override + public ByteBuffer getDataBuffer(long offset, long size) { + assert size < Integer.MAX_VALUE; + return getIndexBuffer(indexSize + offset, size); + } + + @Override + public boolean read(long offset, + ByteBuffer compressedBuffer, long compressedSize, + ByteBuffer uncompressedBuffer, long uncompressedSize) { + assert compressedSize < Integer.MAX_VALUE; + assert uncompressedSize < Integer.MAX_VALUE; + boolean isRead = readBuffer(compressedBuffer, + indexSize + offset, compressedSize); + if (isRead) { + byte[] bytesIn = new byte[(int)compressedSize]; + compressedBuffer.get(bytesIn); + byte[] bytesOut; + try { + bytesOut = decompressor.decompressResource(byteOrder, (int strOffset) -> { + return new UTF8String(getStringBytes(strOffset)).toString(); + }, bytesIn); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + uncompressedBuffer.put(bytesOut); + uncompressedBuffer.rewind(); + } + + return isRead; + } + + @Override + public boolean read(long offset, + ByteBuffer uncompressedBuffer, long uncompressedSize) { + assert uncompressedSize < Integer.MAX_VALUE; + boolean isRead = readBuffer(uncompressedBuffer, + indexSize + offset, uncompressedSize); + + return isRead; + } + + @Override + public byte[] getStringBytes(int offset) { + if (offset == 0) { + return new byte[0]; + } + + int length = strings.length - offset; + + for (int i = offset; i < strings.length; i++) { + if (strings[i] == 0) { + length = i - offset; + break; + } + } + + byte[] bytes = new byte[length]; + System.arraycopy(strings, offset, bytes, 0, length); + + return bytes; + } + + @Override + public long[] getAttributes(int offset) { + return ImageLocationBase.decompress(locations, offset); + } + + @Override + public ImageLocation findLocation(UTF8String name, ImageStringsReader strings) { + int count = header.getTableLength(); + int index = redirect[name.hashCode() % count]; + + if (index < 0) { + index = -index - 1; + } else { + index = name.hashCode(index) % count; + } + + long[] attributes = getAttributes(offsets[index]); + + ImageLocation imageLocation = new ImageLocation(attributes, strings); + + if (!imageLocation.verify(name)) { + return null; + } + + return imageLocation; + } + + @Override + public int[] attributeOffsets() { + return offsets; + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java index c641d29b0fb..148debdf4f0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java @@ -25,369 +25,15 @@ package jdk.internal.jimage; -import java.nio.ByteBuffer; - -public final class ImageLocation { - final static int ATTRIBUTE_END = 0; - final static int ATTRIBUTE_BASE = 1; - final static int ATTRIBUTE_PARENT = 2; - final static int ATTRIBUTE_EXTENSION = 3; - final static int ATTRIBUTE_OFFSET = 4; - final static int ATTRIBUTE_COMPRESSED = 5; - final static int ATTRIBUTE_UNCOMPRESSED = 6; - final static int ATTRIBUTE_COUNT = 7; - - private int locationOffset; - private long[] attributes; - private byte[] bytes; - private final ImageStrings strings; - - private ImageLocation(ImageStrings strings) { - this.strings = strings; +public final class ImageLocation extends ImageLocationBase { + ImageLocation(long[] attributes, ImageStringsReader strings) { + super(attributes, strings); } - void writeTo(ImageStream stream) { - compress(); - locationOffset = stream.getPosition(); - stream.put(bytes, 0, bytes.length); - } + static ImageLocation readFrom(BasicImageReader reader, int offset) { + long[] attributes = reader.getAttributes(offset); + ImageStringsReader strings = reader.getStrings(); - static ImageLocation readFrom(ByteBuffer locationsBuffer, int offset, ImageStrings strings) { - final long[] attributes = new long[ATTRIBUTE_COUNT]; - - for (int i = offset; true; ) { - int data = locationsBuffer.get(i++) & 0xFF; - int kind = attributeKind(data); - assert ATTRIBUTE_END <= kind && kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; - - if (kind == ATTRIBUTE_END) { - break; - } - - int length = attributeLength(data); - long value = 0; - - for (int j = 0; j < length; j++) { - value <<= 8; - value |= locationsBuffer.get(i++) & 0xFF; - } - - attributes[kind] = value; - } - - ImageLocation location = new ImageLocation(strings); - location.attributes = attributes; - - return location; - } - - private static int attributeLength(int data) { - return (data & 0x7) + 1; - } - - private static int attributeKind(int data) { - return data >>> 3; - } - - public boolean verify(UTF8String name) { - UTF8String match = UTF8String.match(name, getParent()); - - if (match == null) { - return false; - } - - match = UTF8String.match(match, getBase()); - - if (match == null) { - return false; - } - - match = UTF8String.match(match, getExtension()); - - return match != null && match.length() == 0; - } - - - long getAttribute(int kind) { - assert ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; - decompress(); - - return attributes[kind]; - } - - UTF8String getAttributeUTF8String(int kind) { - assert ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; - decompress(); - - return strings.get((int)attributes[kind]); - } - - String getAttributeString(int kind) { - return getAttributeUTF8String(kind).toString(); - } - - ImageLocation addAttribute(int kind, long value) { - assert ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; - decompress(); - attributes[kind] = value; - return this; - } - - private void decompress() { - if (attributes == null) { - attributes = new long[ATTRIBUTE_COUNT]; - } - - if (bytes != null) { - for (int i = 0; i < bytes.length; ) { - int data = bytes[i++] & 0xFF; - int kind = attributeKind(data); - - if (kind == ATTRIBUTE_END) { - break; - } - - assert ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; - int length = attributeLength(data); - long value = 0; - - for (int j = 0; j < length; j++) { - value <<= 8; - value |= bytes[i++] & 0xFF; - } - - attributes[kind] = value; - } - - bytes = null; - } - } - - private void compress() { - if (bytes == null) { - ImageStream stream = new ImageStream(16); - - for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) { - long value = attributes[kind]; - - if (value != 0) { - int n = (63 - Long.numberOfLeadingZeros(value)) >> 3; - stream.put((kind << 3) | n); - - for (int i = n; i >= 0; i--) { - stream.put((int)(value >> (i << 3))); - } - } - } - - stream.put(ATTRIBUTE_END << 3); - bytes = stream.toArray(); - attributes = null; - } - } - - static ImageLocation newLocation(UTF8String fullname, ImageStrings strings, long contentOffset, long compressedSize, long uncompressedSize) { - UTF8String base; - UTF8String extension = extension(fullname); - int parentOffset = ImageStrings.EMPTY_OFFSET; - int extensionOffset = ImageStrings.EMPTY_OFFSET; - int baseOffset; - - if (extension.length() != 0) { - UTF8String parent = parent(fullname); - base = base(fullname); - parentOffset = strings.add(parent); - extensionOffset = strings.add(extension); - } else { - base = fullname; - } - - baseOffset = strings.add(base); - - return new ImageLocation(strings) - .addAttribute(ATTRIBUTE_BASE, baseOffset) - .addAttribute(ATTRIBUTE_PARENT, parentOffset) - .addAttribute(ATTRIBUTE_EXTENSION, extensionOffset) - .addAttribute(ATTRIBUTE_OFFSET, contentOffset) - .addAttribute(ATTRIBUTE_COMPRESSED, compressedSize) - .addAttribute(ATTRIBUTE_UNCOMPRESSED, uncompressedSize); - } - - @Override - public int hashCode() { - return getExtension().hashCode(getBase().hashCode(getParent().hashCode())); - } - - int hashCode(int base) { - return getExtension().hashCode(getBase().hashCode(getParent().hashCode(base))); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (!(obj instanceof ImageLocation)) { - return false; - } - - ImageLocation other = (ImageLocation)obj; - - return getBaseOffset() == other.getBaseOffset() && - getParentOffset() == other.getParentOffset() && - getExtensionOffset() == other.getExtensionOffset(); - } - - static UTF8String parent(UTF8String fullname) { - int slash = fullname.lastIndexOf('/'); - - return slash == UTF8String.NOT_FOUND ? UTF8String.EMPTY_STRING : fullname.substring(0, slash + 1); - } - - static UTF8String extension(UTF8String fullname) { - int dot = fullname.lastIndexOf('.'); - - return dot == UTF8String.NOT_FOUND ? UTF8String.EMPTY_STRING : fullname.substring(dot); - } - - static UTF8String base(UTF8String fullname) { - int slash = fullname.lastIndexOf('/'); - - if (slash != UTF8String.NOT_FOUND) { - fullname = fullname.substring(slash + 1); - } - - int dot = fullname.lastIndexOf('.'); - - if (dot != UTF8String.NOT_FOUND) { - fullname = fullname.substring(0, dot); - } - - return fullname; - } - - int getLocationOffset() { - return locationOffset; - } - - UTF8String getBase() { - return getAttributeUTF8String(ATTRIBUTE_BASE); - } - - public String getBaseString() { - return getBase().toString(); - } - - int getBaseOffset() { - return (int)getAttribute(ATTRIBUTE_BASE); - } - - UTF8String getParent() { - return getAttributeUTF8String(ATTRIBUTE_PARENT); - } - - public String getParentString() { - return getParent().toString(); - } - - int getParentOffset() { - return (int)getAttribute(ATTRIBUTE_PARENT); - } - - UTF8String getExtension() { - return getAttributeUTF8String(ATTRIBUTE_EXTENSION); - } - - public String getExtensionString() { - return getExtension().toString(); - } - - int getExtensionOffset() { - return (int)getAttribute(ATTRIBUTE_EXTENSION); - } - - UTF8String getName() { - return getBase().concat(getExtension()); - } - - String getNameString() { - return getName().toString(); - } - - UTF8String getFullname() { - return getParent().concat(getBase(), getExtension()); - } - - String getFullnameString() { - return getFullname().toString(); - } - - public long getContentOffset() { - return getAttribute(ATTRIBUTE_OFFSET); - } - - public long getCompressedSize() { - return getAttribute(ATTRIBUTE_COMPRESSED); - } - - public long getUncompressedSize() { - return getAttribute(ATTRIBUTE_UNCOMPRESSED); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - decompress(); - - for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) { - long value = attributes[kind]; - - if (value == 0) { - continue; - } - - switch (kind) { - case ATTRIBUTE_BASE: - sb.append("Base: "); - sb.append(value); - sb.append(' '); - sb.append(strings.get((int)value).toString()); - break; - - case ATTRIBUTE_PARENT: - sb.append("Parent: "); - sb.append(value); - sb.append(' '); - sb.append(strings.get((int)value).toString()); - break; - - case ATTRIBUTE_EXTENSION: - sb.append("Extension: "); - sb.append(value); - sb.append(' '); - sb.append(strings.get((int)value).toString()); - break; - - case ATTRIBUTE_OFFSET: - sb.append("Offset: "); - sb.append(value); - break; - - case ATTRIBUTE_COMPRESSED: - sb.append("Compressed: "); - sb.append(value); - break; - - case ATTRIBUTE_UNCOMPRESSED: - sb.append("Uncompressed: "); - sb.append(value); - break; - } - - sb.append("; "); - } - - return sb.toString(); + return new ImageLocation(attributes, strings); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocationBase.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocationBase.java new file mode 100644 index 00000000000..65c77315f98 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocationBase.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +public class ImageLocationBase { + final static int ATTRIBUTE_END = 0; + final static int ATTRIBUTE_MODULE = 1; + final static int ATTRIBUTE_PARENT = 2; + final static int ATTRIBUTE_BASE = 3; + final static int ATTRIBUTE_EXTENSION = 4; + final static int ATTRIBUTE_OFFSET = 5; + final static int ATTRIBUTE_COMPRESSED = 6; + final static int ATTRIBUTE_UNCOMPRESSED = 7; + final static int ATTRIBUTE_COUNT = 8; + + protected final long[] attributes; + + protected final ImageStrings strings; + + protected ImageLocationBase(long[] attributes, ImageStrings strings) { + this.attributes = attributes; + this.strings = strings; + } + + ImageStrings getStrings() { + return strings; + } + + private static int attributeLength(int data) { + return (data & 0x7) + 1; + } + + private static int attributeKind(int data) { + return data >>> 3; + } + + static long[] decompress(byte[] bytes) { + return decompress(bytes, 0); + } + + static long[] decompress(byte[] bytes, int offset) { + long[] attributes = new long[ATTRIBUTE_COUNT]; + + if (bytes != null) { + for (int i = offset; i < bytes.length; ) { + int data = bytes[i++] & 0xFF; + int kind = attributeKind(data); + + if (kind == ATTRIBUTE_END) { + break; + } + + assert ATTRIBUTE_END < kind && + kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; + int length = attributeLength(data); + long value = 0; + + for (int j = 0; j < length; j++) { + value <<= 8; + value |= bytes[i++] & 0xFF; + } + + attributes[kind] = value; + } + } + + return attributes; + } + + static byte[] compress(long[] attributes) { + ImageStream stream = new ImageStream(16); + + for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) { + long value = attributes[kind]; + + if (value != 0) { + int n = (63 - Long.numberOfLeadingZeros(value)) >> 3; + stream.put((kind << 3) | n); + + for (int i = n; i >= 0; i--) { + stream.put((int)(value >> (i << 3))); + } + } + } + + stream.put(ATTRIBUTE_END << 3); + + return stream.toArray(); + } + + public boolean verify(UTF8String name) { + return UTF8String.equals(getFullName(), name); + } + + protected long getAttribute(int kind) { + assert ATTRIBUTE_END < kind && + kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; + + return attributes[kind]; + } + + protected UTF8String getAttributeUTF8String(int kind) { + assert ATTRIBUTE_END < kind && + kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; + + return getStrings().get((int)attributes[kind]); + } + + protected String getAttributeString(int kind) { + return getAttributeUTF8String(kind).toString(); + } + + UTF8String getModule() { + return getAttributeUTF8String(ATTRIBUTE_MODULE); + } + + public String getModuleString() { + return getModule().toString(); + } + + int getModuleOffset() { + return (int)getAttribute(ATTRIBUTE_MODULE); + } + + UTF8String getBase() { + return getAttributeUTF8String(ATTRIBUTE_BASE); + } + + public String getBaseString() { + return getBase().toString(); + } + + int getBaseOffset() { + return (int)getAttribute(ATTRIBUTE_BASE); + } + + UTF8String getParent() { + return getAttributeUTF8String(ATTRIBUTE_PARENT); + } + + public String getParentString() { + return getParent().toString(); + } + + int getParentOffset() { + return (int)getAttribute(ATTRIBUTE_PARENT); + } + + UTF8String getExtension() { + return getAttributeUTF8String(ATTRIBUTE_EXTENSION); + } + + public String getExtensionString() { + return getExtension().toString(); + } + + int getExtensionOffset() { + return (int)getAttribute(ATTRIBUTE_EXTENSION); + } + + UTF8String getFullName() { + return getFullName(false); + } + + UTF8String getFullName(boolean modulesPrefix) { + // Note: Consider a UTF8StringBuilder. + UTF8String fullName = UTF8String.EMPTY_STRING; + + if (getModuleOffset() != 0) { + fullName = fullName.concat( + // TODO The use of UTF8String.MODULES_STRING does not belong here. + modulesPrefix? UTF8String.MODULES_STRING : + UTF8String.EMPTY_STRING, + UTF8String.SLASH_STRING, + getModule(), + UTF8String.SLASH_STRING); + } + + if (getParentOffset() != 0) { + fullName = fullName.concat(getParent(), + UTF8String.SLASH_STRING); + } + + fullName = fullName.concat(getBase()); + + if (getExtensionOffset() != 0) { + fullName = fullName.concat(UTF8String.DOT_STRING, + getExtension()); + } + + return fullName; + } + + UTF8String buildName(boolean includeModule, boolean includeParent, + boolean includeName) { + // Note: Consider a UTF8StringBuilder. + UTF8String name = UTF8String.EMPTY_STRING; + + if (includeModule && getModuleOffset() != 0) { + name = name.concat(UTF8String.MODULES_STRING, + UTF8String.SLASH_STRING, + getModule()); + } + + if (includeParent && getParentOffset() != 0) { + name = name.concat(UTF8String.SLASH_STRING, + getParent()); + } + + if (includeName) { + if (includeModule || includeParent) { + name = name.concat(UTF8String.SLASH_STRING); + } + + name = name.concat(getBase()); + + if (getExtensionOffset() != 0) { + name = name.concat(UTF8String.DOT_STRING, + getExtension()); + } + } + + return name; + } + + String getFullNameString() { + return getFullName().toString(); + } + + public long getContentOffset() { + return getAttribute(ATTRIBUTE_OFFSET); + } + + public long getCompressedSize() { + return getAttribute(ATTRIBUTE_COMPRESSED); + } + + public long getUncompressedSize() { + return getAttribute(ATTRIBUTE_UNCOMPRESSED); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocationWriter.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocationWriter.java new file mode 100644 index 00000000000..de7625b0f18 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocationWriter.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +public final class ImageLocationWriter extends ImageLocationBase { + private int locationOffset; + + private ImageLocationWriter(ImageStringsWriter strings) { + super(new long[ATTRIBUTE_COUNT], strings); + } + + void writeTo(ImageStream stream) { + byte[] bytes = ImageLocation.compress(attributes); + locationOffset = stream.getPosition(); + stream.put(bytes, 0, bytes.length); + } + + private ImageLocationWriter addAttribute(int kind, long value) { + assert ATTRIBUTE_END < kind && + kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; + attributes[kind] = value; + return this; + } + + private ImageLocationWriter addAttribute(int kind, UTF8String value) { + return addAttribute(kind, strings.add(value)); + } + + static ImageLocationWriter newLocation(UTF8String fullName, + ImageStringsWriter strings, + long contentOffset, long compressedSize, long uncompressedSize) { + UTF8String moduleName = UTF8String.EMPTY_STRING; + UTF8String parentName = UTF8String.EMPTY_STRING; + UTF8String baseName; + UTF8String extensionName = UTF8String.EMPTY_STRING; + + int offset = fullName.indexOf('/', 1); + if (fullName.length() >= 2 && fullName.charAt(0) == '/' && offset != -1) { + moduleName = fullName.substring(1, offset - 1); + fullName = fullName.substring(offset + 1); + } + + offset = fullName.lastIndexOf('/'); + if (offset != -1) { + parentName = fullName.substring(0, offset); + fullName = fullName.substring(offset + 1); + } + + offset = fullName.lastIndexOf('.'); + if (offset != -1) { + baseName = fullName.substring(0, offset); + extensionName = fullName.substring(offset + 1); + } else { + baseName = fullName; + } + + return new ImageLocationWriter(strings) + .addAttribute(ATTRIBUTE_MODULE, moduleName) + .addAttribute(ATTRIBUTE_PARENT, parentName) + .addAttribute(ATTRIBUTE_BASE, baseName) + .addAttribute(ATTRIBUTE_EXTENSION, extensionName) + .addAttribute(ATTRIBUTE_OFFSET, contentOffset) + .addAttribute(ATTRIBUTE_COMPRESSED, compressedSize) + .addAttribute(ATTRIBUTE_UNCOMPRESSED, uncompressedSize); + } + + @Override + public int hashCode() { + return hashCode(UTF8String.HASH_MULTIPLIER); + } + + int hashCode(int seed) { + int hash = seed; + + if (getModuleOffset() != 0) { + hash = UTF8String.SLASH_STRING.hashCode(hash); + hash = getModule().hashCode(hash); + hash = UTF8String.SLASH_STRING.hashCode(hash); + } + + if (getParentOffset() != 0) { + hash = getParent().hashCode(hash); + hash = UTF8String.SLASH_STRING.hashCode(hash); + } + + hash = getBase().hashCode(hash); + + if (getExtensionOffset() != 0) { + hash = UTF8String.DOT_STRING.hashCode(hash); + hash = getExtension().hashCode(hash); + } + + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof ImageLocationWriter)) { + return false; + } + + ImageLocation other = (ImageLocation)obj; + + return getModuleOffset() == other.getModuleOffset() && + getParentOffset() == other.getParentOffset() && + getBaseOffset() == other.getBaseOffset() && + getExtensionOffset() == other.getExtensionOffset(); + } + + int getLocationOffset() { + return locationOffset; + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleData.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleData.java new file mode 100644 index 00000000000..e48375415ab --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleData.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/* + * Manage module meta data. + * + * NOTE: needs revision. + * Each loader requires set of module meta data to identify which modules and + * packages are managed by that loader. Currently, there is one image file per + * loader, so only one module meta data resource per file. + * + * Each element in the module meta data is a native endian 4 byte integer. Note + * that entries with zero offsets for string table entries should be ignored ( + * padding for hash table lookup.) + * + * Format: + * Count of package to module entries + * Count of module to package entries + * Perfect Hash redirect table[Count of package to module entries] + * Package to module entries[Count of package to module entries] + * Offset to package name in string table + * Offset to module name in string table + * Perfect Hash redirect table[Count of module to package entries] + * Module to package entries[Count of module to package entries] + * Offset to module name in string table + * Count of packages in module + * Offset to first package in packages table + * Packages[] + * Offset to package name in string table + */ + +final public class ImageModuleData { + public final static String META_DATA_EXTENSION = ".jdata"; + public final static String SEPARATOR = "\t"; + public final static int NOT_FOUND = -1; + private final static int ptmCountOffset = 0; + private final static int mtpCountOffset = 1; + private final static int ptmRedirectOffset = 2; + private final static int dataNameOffset = 0; + private final static int ptmDataWidth = 2; + private final static int ptmDataModuleOffset = 1; + private final static int mtpDataWidth = 3; + private final static int mtpDataCountOffset = 1; + private final static int mtpDataOffsetOffset = 2; + + private final BasicImageReader reader; + private final IntBuffer intBuffer; + private final int ptmRedirectLength; + private final int mtpRedirectLength; + private final int ptmDataOffset; + private final int mtpRedirectOffset; + private final int mtpDataOffset; + private final int mtpPackagesOffset; + + public ImageModuleData(BasicImageReader reader) { + this(reader, getBytes(reader)); + } + + public ImageModuleData(BasicImageReader reader, byte[] bytes) { + this.reader = reader; + + ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(reader.getByteOrder()); + this.intBuffer = byteBuffer.asIntBuffer(); + + this.ptmRedirectLength = get(ptmCountOffset); + this.mtpRedirectLength = get(mtpCountOffset); + + this.ptmDataOffset = ptmRedirectOffset + ptmRedirectLength; + this.mtpRedirectOffset = ptmDataOffset + ptmRedirectLength * ptmDataWidth; + this.mtpDataOffset = mtpRedirectOffset + mtpRedirectLength; + this.mtpPackagesOffset = mtpDataOffset + mtpRedirectLength * mtpDataWidth; + } + + private static byte[] getBytes(BasicImageReader reader) { + String loaderName = reader.imagePathName(); + + if (loaderName.endsWith(BasicImageWriter.IMAGE_EXT)) { + loaderName = loaderName.substring(0, loaderName.length() - + BasicImageWriter.IMAGE_EXT.length()); + } + + byte[] bytes = reader.getResource(getModuleDataName(loaderName)); + + if (bytes == null) { + throw new InternalError("module data missing"); + } + + return bytes; + } + + public List fromModulePackages() { + List lines = new ArrayList<>(); + + for (int i = 0; i < mtpRedirectLength; i++) { + int index = mtpDataOffset + i * mtpDataWidth; + int offset = get(index + dataNameOffset); + + if (offset != 0) { + StringBuilder sb = new StringBuilder(); + + sb.append(getString(offset)); + + int count = get(index + mtpDataCountOffset); + int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset; + + for (int j = 0; j < count; j++) { + sb.append(SEPARATOR); + sb.append(stringAt(base + j)); + } + + lines.add(sb.toString()); + } + } + + return lines; + } + + public static String getModuleDataName(String loaderName) { + return loaderName + META_DATA_EXTENSION; + } + + private int get(int index) { + return intBuffer.get(index); + } + + private String getString(int offset) { + return reader.getString(offset); + } + + private String stringAt(int index) { + return reader.getString(get(index)); + } + + private UTF8String getUTF8String(int offset) { + return reader.getUTF8String(offset); + } + + private UTF8String utf8StringAt(int index) { + return reader.getUTF8String(get(index)); + } + + private int find(UTF8String name, int baseOffset, int length, int width) { + if (length == 0) { + return NOT_FOUND; + } + + int hashCode = name.hashCode(); + int index = hashCode % length; + int value = get(baseOffset + index); + + if (value > 0 ) { + hashCode = name.hashCode(value); + index = hashCode % length; + } else if (value < 0) { + index = -1 - value; + } else { + return NOT_FOUND; + } + + index = baseOffset + length + index * width; + + if (!utf8StringAt(index + dataNameOffset).equals(name)) { + return NOT_FOUND; + } + + return index; + } + + public String packageToModule(String packageName) { + UTF8String moduleName = packageToModule(new UTF8String(packageName)); + + return moduleName != null ? moduleName.toString() : null; + } + + public UTF8String packageToModule(UTF8String packageName) { + int index = find(packageName, ptmRedirectOffset, ptmRedirectLength, ptmDataWidth); + + if (index != NOT_FOUND) { + return utf8StringAt(index + ptmDataModuleOffset); + } + + return null; + } + + public List moduleToPackages(String moduleName) { + int index = find(new UTF8String(moduleName), mtpRedirectOffset, + mtpRedirectLength, mtpDataWidth); + + if (index != NOT_FOUND) { + int count = get(index + mtpDataCountOffset); + int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset; + List packages = new ArrayList<>(count); + + for (int i = 0; i < count; i++) { + packages.add(stringAt(base + i)); + } + + return packages; + } + + return null; + } + + public List allPackageNames() { + List packages = new ArrayList<>(); + + for (int i = 0; i < ptmRedirectLength; i++) { + int offset = get(ptmDataOffset + i * ptmDataWidth + dataNameOffset); + + if (offset != 0) { + packages.add(getString(offset)); + } + } + + return packages; + } + + public Set allModuleNames() { + Set modules = new HashSet<>(); + + for (int i = 0; i < mtpRedirectLength; i++) { + int index = mtpDataOffset + i * mtpDataWidth; + int offset = get(index + dataNameOffset); + + if (offset != 0) { + modules.add(getString(offset)); + } + } + + return modules; + } + + public Map packageModuleMap() { + Map map = new HashMap<>(); + + for (int i = 0; i < mtpRedirectLength; i++) { + int index = mtpDataOffset + i * mtpDataWidth; + int offset = get(index + dataNameOffset); + + if (offset != 0) { + String moduleName = getString(offset); + + int count = get(index + mtpDataCountOffset); + int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset; + + for (int j = 0; j < count; j++) { + map.put(stringAt(base + j), moduleName); + } + } + } + + return map; + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleDataWriter.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleDataWriter.java new file mode 100644 index 00000000000..057c2883183 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleDataWriter.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ImageModuleDataWriter { + final byte[] bytes; + + public ImageModuleDataWriter(BasicImageWriter writer, + Map> modulePackages) { + PerfectHashBuilder packageToModule = new PerfectHashBuilder<>( + new PerfectHashBuilder.Entry().getClass(), + new PerfectHashBuilder.Bucket().getClass()); + PerfectHashBuilder> moduleToPackages = new PerfectHashBuilder<>( + new PerfectHashBuilder.Entry>().getClass(), + new PerfectHashBuilder.Bucket>().getClass()); + + modulePackages.entrySet().stream().forEach((entry) -> { + String moduleName = entry.getKey(); + List packages = entry.getValue(); + packages.stream().forEach((packageName) -> { + packageToModule.put(packageName, moduleName); + }); + + moduleToPackages.put(moduleName, packages); + }); + + packageToModule.generate(); + moduleToPackages.generate(); + + bytes = getBytes(writer, packageToModule, moduleToPackages); + } + + public static ImageModuleDataWriter buildModuleData(BasicImageWriter writer, + Map> modulePackagesMap) { + Set modules = modulePackagesMap.keySet(); + + Map> modulePackages = new LinkedHashMap<>(); + modules.stream().sorted().forEach((moduleName) -> { + List localPackages = modulePackagesMap.get(moduleName).stream() + .map(pn -> pn.replace('.', '/')) + .sorted() + .collect(Collectors.toList()); + modulePackages.put(moduleName, localPackages); + }); + + return new ImageModuleDataWriter(writer, modulePackages); + } + + public static Map> toModulePackages(List lines) { + Map> modulePackages = new LinkedHashMap<>(); + + for (String line : lines) { + String[] parts = line.split(ImageModuleData.SEPARATOR); + String moduleName = parts[0]; + List packages = Arrays.asList(Arrays.copyOfRange(parts, 1, parts.length)); + modulePackages.put(moduleName, packages); + } + + return modulePackages; + } + + public void addLocation(String name, BasicImageWriter writer) { + writer.addLocation(ImageModuleData.getModuleDataName(name), 0, 0, bytes.length); + } + + private byte[] getBytes(BasicImageWriter writer, + PerfectHashBuilder packageToModule, + PerfectHashBuilder> moduleToPackages) { + ImageStream stream = new ImageStream(writer.getByteOrder()); + + int[] ptmRedirect = packageToModule.getRedirect(); + int[] mtpRedirect = moduleToPackages.getRedirect(); + PerfectHashBuilder.Entry[] ptmOrder = packageToModule.getOrder(); + PerfectHashBuilder.Entry>[] mtpOrder = moduleToPackages.getOrder(); + + stream.putInt(ptmRedirect.length); + stream.putInt(mtpRedirect.length); + + for (int value : ptmRedirect) { + stream.putInt(value); + } + + for (PerfectHashBuilder.Entry entry : ptmOrder) { + if (entry != null) { + stream.putInt(writer.addString(entry.getKey())); + stream.putInt(writer.addString(entry.getValue())); + } else { + stream.putInt(0); + stream.putInt(0); + } + } + + for (int value : mtpRedirect) { + stream.putInt(value); + } + + int index = 0; + + for (PerfectHashBuilder.Entry> entry : mtpOrder) { + if (entry != null) { + int count = entry.getValue().size(); + stream.putInt(writer.addString(entry.getKey())); + stream.putInt(count); + stream.putInt(index); + index += count; + } else { + stream.putInt(0); + stream.putInt(0); + stream.putInt(0); + } + } + + for (PerfectHashBuilder.Entry> entry : mtpOrder) { + if (entry != null) { + List value = entry.getValue(); + value.stream().forEach((packageName) -> { + stream.putInt(writer.addString(packageName)); + }); + } + } + + return stream.toArray(); + } + + public void writeTo(DataOutputStream out) throws IOException { + out.write(bytes, 0, bytes.length); + } + + public int size() { + return bytes.length; + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModules.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModules.java deleted file mode 100644 index 3c1e5d3c83b..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModules.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * 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.jimage; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import static jdk.internal.jimage.PackageModuleMap.*; - -public class ImageModules { - protected final Map loaders = new LinkedHashMap<>(); - protected final Map> localPkgs = new HashMap<>(); - - protected ImageModules() {} - - public ImageModules(Set bootModules, - Set extModules, - Set appModules) throws IOException { - mapModulesToLoader(Loader.BOOT_LOADER, bootModules); - mapModulesToLoader(Loader.EXT_LOADER, extModules); - mapModulesToLoader(Loader.APP_LOADER, appModules); - } - - public Map> packages() { - return localPkgs; - } - - // ## FIXME: should be package-private - // When jlink legacy format support is removed, it should - // use the package table in the jimage. - public void setPackages(String mn, Set pkgs) { - localPkgs.put(mn, pkgs); - } - - /* - * Returns the name of modules mapped to a given class loader in the image - */ - public Set getModules(Loader type) { - if (loaders.containsKey(type)) { - return loaders.get(type).modules(); - } else { - return Collections.emptySet(); - } - } - - private void mapModulesToLoader(Loader loader, Set modules) { - if (modules.isEmpty()) - return; - - // put java.base first - Set mods = new LinkedHashSet<>(); - modules.stream() - .filter(m -> m.equals("java.base")) - .forEach(mods::add); - modules.stream().sorted() - .filter(m -> !m.equals("java.base")) - .forEach(mods::add); - loaders.put(loader, new LoaderModuleData(loader, mods)); - } - - enum Loader { - BOOT_LOADER(0, "bootmodules"), - EXT_LOADER(1, "extmodules"), - APP_LOADER(2, "appmodules"); // ## may be more than 1 loader - - final int id; - final String name; - Loader(int id, String name) { - this.id = id; - this.name = name; - } - - String getName() { - return name; - } - static Loader get(int id) { - switch (id) { - case 0: return BOOT_LOADER; - case 1: return EXT_LOADER; - case 2: return APP_LOADER; - default: - throw new IllegalArgumentException("invalid loader id: " + id); - } - } - public int id() { return id; } - } - - public class LoaderModuleData { - private final Loader loader; - private final Set modules; - LoaderModuleData(Loader loader, Set modules) { - this.loader = loader; - this.modules = Collections.unmodifiableSet(modules); - } - - Set modules() { - return modules; - } - Loader loader() { return loader; } - } - - ModuleIndex buildModuleIndex(Loader type, BasicImageWriter writer) { - return new ModuleIndex(getModules(type), writer); - } - - /* - * Generate module name table and the package map as resources - * in the modular image - */ - public class ModuleIndex { - final Map moduleOffsets = new LinkedHashMap<>(); - final Map> packageOffsets = new HashMap<>(); - final int size; - public ModuleIndex(Set mods, BasicImageWriter writer) { - // module name offsets - writer.addLocation(MODULES_ENTRY, 0, 0, mods.size() * 4); - long offset = mods.size() * 4; - for (String mn : mods) { - moduleOffsets.put(mn, writer.addString(mn)); - List poffsets = localPkgs.get(mn).stream() - .map(pn -> pn.replace('.', '/')) - .map(writer::addString) - .collect(Collectors.toList()); - // package name offsets per module - String entry = mn + "/" + PACKAGES_ENTRY; - int bytes = poffsets.size() * 4; - writer.addLocation(entry, offset, 0, bytes); - offset += bytes; - packageOffsets.put(mn, poffsets); - } - this.size = (int) offset; - } - - void writeTo(DataOutputStream out) throws IOException { - for (int moffset : moduleOffsets.values()) { - out.writeInt(moffset); - } - for (String mn : moduleOffsets.keySet()) { - for (int poffset : packageOffsets.get(mn)) { - out.writeInt(poffset); - } - } - } - - int size() { - return size; - } - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java new file mode 100644 index 00000000000..34dc378f89f --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import sun.misc.JavaNioAccess; +import sun.misc.SharedSecrets; + +final class ImageNativeSubstrate implements ImageSubstrate { + private static final JavaNioAccess NIOACCESS = + SharedSecrets.getJavaNioAccess(); + + private final long id; + private final long indexAddress; + private final long dataAddress; + + native static long openImage(String imagePath, boolean bigEndian); + native static void closeImage(long id); + native static long getIndexAddress(long id); + native static long getDataAddress(long id); + native static boolean readCompressed(long id, long offset, + ByteBuffer compressedBuffer, long compressedSize, + ByteBuffer uncompressedBuffer, long uncompressedSize); + native static boolean read(long id, long offset, + ByteBuffer uncompressedBuffer, long uncompressedSize); + native static byte[] getStringBytes(long id, int offset); + native static long[] getAttributes(long id, int offset); + native static long[] findAttributes(long id, byte[] path); + native static int[] attributeOffsets(long id); + + static ByteBuffer newDirectByteBuffer(long address, long capacity) { + assert capacity < Integer.MAX_VALUE; + return NIOACCESS.newDirectByteBuffer(address, (int)capacity, null); + } + + private ImageNativeSubstrate(long id) { + this.id = id; + this.indexAddress = getIndexAddress(id); + this.dataAddress = getDataAddress(id); + } + + static ImageSubstrate openImage(String imagePath, ByteOrder byteOrder) + throws IOException { + long id = openImage(imagePath, byteOrder == ByteOrder.BIG_ENDIAN); + + if (id == 0) { + throw new IOException("Image not found \"" + imagePath + "\""); + } + + return new ImageNativeSubstrate(id); + } + + @Override + public void close() { + closeImage(id); + } + + @Override + public ByteBuffer getIndexBuffer(long offset, long size) { + return newDirectByteBuffer(indexAddress + offset, size); + } + + @Override + public ByteBuffer getDataBuffer(long offset, long size) { + return dataAddress != 0 ? + newDirectByteBuffer(dataAddress + offset, size) : null; + } + + @Override + public boolean supportsDataBuffer() { + return dataAddress != 0; + } + + @Override + public boolean read(long offset, + ByteBuffer compressedBuffer, long compressedSize, + ByteBuffer uncompressedBuffer, long uncompressedSize) { + return readCompressed(id, offset, + compressedBuffer, compressedSize, + uncompressedBuffer, uncompressedSize); + } + + @Override + public boolean read(long offset, + ByteBuffer uncompressedBuffer, long uncompressedSize) { + return read(id, offset, uncompressedBuffer, uncompressedSize); + } + + @Override + public byte[] getStringBytes(int offset) { + return getStringBytes(id, offset); + } + + @Override + public long[] getAttributes(int offset) { + return getAttributes(id, offset); + } + + @Override + public ImageLocation findLocation(UTF8String name, ImageStringsReader strings) { + long[] attributes = findAttributes(id, name.getBytes()); + + return attributes != null ? new ImageLocation(attributes, strings) : null; + } + + @Override + public int[] attributeOffsets() { + return attributeOffsets(id); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java index d28da36fa2f..2798d732f63 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java @@ -26,12 +26,10 @@ package jdk.internal.jimage; import java.io.IOException; import java.io.UncheckedIOException; -import java.net.URI; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.nio.file.Files; -import java.nio.file.FileSystem; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; import java.nio.file.Paths; @@ -42,13 +40,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; -import java.util.function.Supplier; +import static jdk.internal.jimage.UTF8String.*; public class ImageReader extends BasicImageReader { // well-known strings needed for image file system. - static final UTF8String ROOT = new UTF8String("/"); - static final UTF8String META_INF = new UTF8String("/META-INF"); - static final UTF8String PACKAGES_OFFSETS = new UTF8String("packages.offsets"); + static final UTF8String ROOT_STRING = UTF8String.SLASH_STRING; // attributes of the .jimage file. jimage file does not contain // attributes for the individual resources (yet). We use attributes @@ -56,15 +52,18 @@ public class ImageReader extends BasicImageReader { // Iniitalized lazily, see {@link #imageFileAttributes()}. private BasicFileAttributes imageFileAttributes; - private final Map packageMap; + private final ImageModuleData moduleData; // directory management implementation private final Map nodes; private volatile Directory rootDir; + private Directory packagesDir; + private Directory modulesDir; + ImageReader(String imagePath, ByteOrder byteOrder) throws IOException { super(imagePath, byteOrder); - this.packageMap = PackageModuleMap.readFrom(this); + this.moduleData = new ImageModuleData(this); this.nodes = Collections.synchronizedMap(new HashMap<>()); } @@ -89,11 +88,42 @@ public class ImageReader extends BasicImageReader { clearNodes(); } + @Override + public ImageLocation findLocation(UTF8String name) { + ImageLocation location = super.findLocation(name); + + // NOTE: This should be removed when module system is up in full. + if (location == null) { + int index = name.lastIndexOf('/'); + + if (index != -1) { + UTF8String packageName = name.substring(0, index); + UTF8String moduleName = moduleData.packageToModule(packageName); + + if (moduleName != null) { + UTF8String fullName = UTF8String.SLASH_STRING.concat(moduleName, + UTF8String.SLASH_STRING, name); + location = super.findLocation(fullName); + } + } else { + // No package, try all modules. + for (String mod : moduleData.allModuleNames()) { + location = super.findLocation("/" + mod + "/" + name); + if (location != null) { + break; + } + } + } + } + + return location; + } + /** * Return the module name that contains the given package name. */ - public String getModule(String pkg) { - return packageMap.get(pkg); + public String getModule(String packageName) { + return moduleData.packageToModule(packageName); } // jimage file does not store directory structure. We build nodes @@ -101,14 +131,13 @@ public class ImageReader extends BasicImageReader { // Node can be a directory or a resource public static abstract class Node { private static final int ROOT_DIR = 0b0000_0000_0000_0001; - private static final int MODULE_DIR = 0b0000_0000_0000_0010; - private static final int METAINF_DIR = 0b0000_0000_0000_0100; - private static final int TOPLEVEL_PKG_DIR = 0b0000_0000_0000_1000; - private static final int HIDDEN = 0b0000_0000_0001_0000; + private static final int PACKAGES_DIR = 0b0000_0000_0000_0010; + private static final int MODULES_DIR = 0b0000_0000_0000_0100; private int flags; private final UTF8String name; private final BasicFileAttributes fileAttrs; + private boolean completed; Node(UTF8String name, BasicFileAttributes fileAttrs) { assert name != null; @@ -117,6 +146,19 @@ public class ImageReader extends BasicImageReader { this.fileAttrs = fileAttrs; } + /** + * A node is completed when all its direct children have been built. + * + * @return + */ + public boolean isCompleted() { + return completed; + } + + public void setCompleted(boolean completed) { + this.completed = completed; + } + public final void setIsRootDir() { flags |= ROOT_DIR; } @@ -125,40 +167,20 @@ public class ImageReader extends BasicImageReader { return (flags & ROOT_DIR) != 0; } - public final void setIsModuleDir() { - flags |= MODULE_DIR; + public final void setIsPackagesDir() { + flags |= PACKAGES_DIR; } - public final boolean isModuleDir() { - return (flags & MODULE_DIR) != 0; + public final boolean isPackagesDir() { + return (flags & PACKAGES_DIR) != 0; } - public final void setIsMetaInfDir() { - flags |= METAINF_DIR; + public final void setIsModulesDir() { + flags |= MODULES_DIR; } - public final boolean isMetaInfDir() { - return (flags & METAINF_DIR) != 0; - } - - public final void setIsTopLevelPackageDir() { - flags |= TOPLEVEL_PKG_DIR; - } - - public final boolean isTopLevelPackageDir() { - return (flags & TOPLEVEL_PKG_DIR) != 0; - } - - public final void setIsHidden() { - flags |= HIDDEN; - } - - public final boolean isHidden() { - return (flags & HIDDEN) != 0; - } - - public final boolean isVisible() { - return !isHidden(); + public final boolean isModulesDir() { + return (flags & MODULES_DIR) != 0; } public final UTF8String getName() { @@ -169,6 +191,20 @@ public class ImageReader extends BasicImageReader { return fileAttrs; } + // resolve this Node (if this is a soft link, get underlying Node) + public final Node resolveLink() { + return resolveLink(false); + } + + public Node resolveLink(boolean recursive) { + return this; + } + + // is this a soft link Node? + public boolean isLink() { + return false; + } + public boolean isDirectory() { return false; } @@ -242,16 +278,20 @@ public class ImageReader extends BasicImageReader { } // directory node - directory has full path name without '/' at end. - public static final class Directory extends Node { + static final class Directory extends Node { private final List children; - @SuppressWarnings("LeakingThisInConstructor") - Directory(Directory parent, UTF8String name, BasicFileAttributes fileAttrs) { + private Directory(Directory parent, UTF8String name, BasicFileAttributes fileAttrs) { super(name, fileAttrs); children = new ArrayList<>(); + } + + static Directory create(Directory parent, UTF8String name, BasicFileAttributes fileAttrs) { + Directory dir = new Directory(parent, name, fileAttrs); if (parent != null) { - parent.addChild(this); + parent.addChild(dir); } + return dir; } @Override @@ -259,6 +299,7 @@ public class ImageReader extends BasicImageReader { return true; } + @Override public List getChildren() { return Collections.unmodifiableList(children); } @@ -281,19 +322,33 @@ public class ImageReader extends BasicImageReader { // "resource" is .class or any other resource (compressed/uncompressed) in a jimage. // full path of the resource is the "name" of the resource. - public static class Resource extends Node { + static class Resource extends Node { private final ImageLocation loc; - @SuppressWarnings("LeakingThisInConstructor") - Resource(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) { - this(parent, ROOT.concat(loc.getFullname()), loc, fileAttrs); + private Resource(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) { + this(parent, loc.getFullName(true), loc, fileAttrs); } - @SuppressWarnings("LeakingThisInConstructor") - Resource(Directory parent, UTF8String name, ImageLocation loc, BasicFileAttributes fileAttrs) { + private Resource(Directory parent, UTF8String name, ImageLocation loc, BasicFileAttributes fileAttrs) { super(name, fileAttrs); this.loc = loc; - parent.addChild(this); + } + + static Resource create(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) { + Resource resource = new Resource(parent, loc, fileAttrs); + parent.addChild(resource); + return resource; + } + + static Resource create(Directory parent, UTF8String name, ImageLocation loc, BasicFileAttributes fileAttrs) { + Resource resource = new Resource(parent, name, loc, fileAttrs); + parent.addChild(resource); + return resource; + } + + @Override + public boolean isCompleted() { + return true; } @Override @@ -327,6 +382,37 @@ public class ImageReader extends BasicImageReader { } } + // represents a soft link to another Node + static class LinkNode extends Node { + private final Node link; + + private LinkNode(Directory parent, UTF8String name, Node link) { + super(name, link.getFileAttributes()); + this.link = link; + } + + static LinkNode create(Directory parent, UTF8String name, Node link) { + LinkNode linkNode = new LinkNode(parent, name, link); + parent.addChild(linkNode); + return linkNode; + } + + @Override + public boolean isCompleted() { + return true; + } + + @Override + public Node resolveLink(boolean recursive) { + return recursive && (link instanceof LinkNode)? ((LinkNode)link).resolveLink(true) : link; + } + + @Override + public boolean isLink() { + return true; + } + } + // directory management interface public Directory getRootDirectory() { return buildRootDirectory(); @@ -340,9 +426,154 @@ public class ImageReader extends BasicImageReader { return findNode(new UTF8String(name)); } + /** + * To visit sub tree resources. + */ + interface LocationVisitor { + + void visit(ImageLocation loc); + } + + /** + * Lazily build a node from a name. + */ + private final class NodeBuilder { + + private static final int SIZE_OF_OFFSET = 4; + + private final UTF8String name; + + private NodeBuilder(UTF8String name) { + this.name = name; + } + + private Node buildNode() { + Node n = null; + boolean isPackages = false; + boolean isModules = false; + String strName = name.toString(); + if (strName.startsWith("" + PACKAGES_STRING)) { + isPackages = true; + } else { + if (strName.startsWith("" + MODULES_STRING)) { + isModules = true; + } + } + if (!isModules && !isPackages) { + return null; + } + + ImageLocation loc = findLocation(name); + + if (loc != null) { // A sub tree node + if (isPackages) { + n = handlePackages(strName, loc); + } else { // modules sub tree + n = handleModulesSubTree(strName, loc); + } + } else { // Asking for a resource? /modules/java.base/java/lang/Object.class + if (isModules) { + n = handleResource(strName, loc); + } + } + return n; + } + + private void visitLocation(ImageLocation loc, LocationVisitor visitor) { + byte[] offsets = getResource(loc); + ByteBuffer buffer = ByteBuffer.wrap(offsets); + buffer.order(getByteOrder()); + IntBuffer intBuffer = buffer.asIntBuffer(); + for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) { + int offset = intBuffer.get(i); + ImageLocation pkgLoc = getLocation(offset); + visitor.visit(pkgLoc); + } + } + + private Node handlePackages(String name, ImageLocation loc) { + long size = loc.getUncompressedSize(); + Node n = null; + // Only possiblities are /packages, /packages/package/module + if (name.equals("" + PACKAGES_STRING)) { + visitLocation(loc, (childloc) -> { + findNode(childloc.getFullName()); + }); + packagesDir.setCompleted(true); + n = packagesDir; + } else { + if (size != 0) { // children are links to module + String pkgName = getBaseExt(loc); + Directory pkgDir = newDirectory(packagesDir, + packagesDir.getName().concat(SLASH_STRING, new UTF8String(pkgName))); + visitLocation(loc, (childloc) -> { + findNode(childloc.getFullName()); + }); + pkgDir.setCompleted(true); + n = pkgDir; + } else { // Link to module + String pkgName = loc.getParentString(); + String modName = getBaseExt(loc); + Node targetNode = findNode(MODULES_STRING + "/" + modName); + if (targetNode != null) { + UTF8String pkgDirName = packagesDir.getName().concat(SLASH_STRING, new UTF8String(pkgName)); + Directory pkgDir = (Directory) nodes.get(pkgDirName); + Node linkNode = newLinkNode(pkgDir, + pkgDir.getName().concat(SLASH_STRING, new UTF8String(modName)), targetNode); + n = linkNode; + } + } + } + return n; + } + + private Node handleModulesSubTree(String name, ImageLocation loc) { + Node n; + Directory dir = makeDirectories(loc.getFullName()); + visitLocation(loc, (childloc) -> { + String path = childloc.getFullNameString(); + if (path.startsWith(MODULES_STRING.toString())) { // a package + makeDirectories(childloc.getFullName()); + } else { // a resource + makeDirectories(childloc.buildName(true, true, false)); + newResource(dir, childloc); + } + }); + dir.setCompleted(true); + n = dir; + return n; + } + + private Node handleResource(String name, ImageLocation loc) { + Node n = null; + String locationPath = name.substring((MODULES_STRING).length()); + ImageLocation resourceLoc = findLocation(locationPath); + if (resourceLoc != null) { + Directory dir = makeDirectories(resourceLoc.buildName(true, true, false)); + Resource res = newResource(dir, resourceLoc); + n = res; + } + return n; + } + + private String getBaseExt(ImageLocation loc) { + String base = loc.getBaseString(); + String ext = loc.getExtensionString(); + if (ext != null && !ext.isEmpty()) { + base = base + "." + ext; + } + return base; + } + } + public synchronized Node findNode(UTF8String name) { buildRootDirectory(); - return nodes.get(name); + Node n = nodes.get(name); + if (n == null || !n.isCompleted()) { + NodeBuilder builder = new NodeBuilder(name); + n = builder.buildNode(); + } + return n; } private synchronized void clearNodes() { @@ -375,65 +606,61 @@ public class ImageReader extends BasicImageReader { // FIXME no time information per resource in jimage file (yet?) // we use file attributes of jimage itself. // root directory - rootDir = new Directory(null, ROOT, imageFileAttributes()); + rootDir = newDirectory(null, ROOT_STRING); rootDir.setIsRootDir(); - nodes.put(rootDir.getName(), rootDir); - ImageLocation[] locs = getAllLocations(true); - for (ImageLocation loc : locs) { - UTF8String parent = loc.getParent(); - // directory where this location goes as child - Directory dir; - if (parent == null || parent.isEmpty()) { - // top level entry under root - dir = rootDir; - } else { - int idx = parent.lastIndexOf('/'); - assert idx != -1 : "invalid parent string"; - UTF8String name = ROOT.concat(parent.substring(0, idx)); - dir = (Directory) nodes.get(name); - if (dir == null) { - // make all parent directories (as needed) - dir = makeDirectories(parent); - } - } - Resource entry = new Resource(dir, loc, imageFileAttributes()); - nodes.put(entry.getName(), entry); - } + // /packages dir + packagesDir = newDirectory(rootDir, PACKAGES_STRING); + packagesDir.setIsPackagesDir(); - Node metaInf = nodes.get(META_INF); - if (metaInf instanceof Directory) { - metaInf.setIsMetaInfDir(); - ((Directory)metaInf).walk(Node::setIsHidden); - } - - fillPackageModuleInfo(); + // /modules dir + modulesDir = newDirectory(rootDir, MODULES_STRING); + modulesDir.setIsModulesDir(); + rootDir.setCompleted(true); return rootDir; } private Directory newDirectory(Directory parent, UTF8String name) { - Directory dir = new Directory(parent, name, imageFileAttributes()); + Directory dir = Directory.create(parent, name, imageFileAttributes()); nodes.put(dir.getName(), dir); return dir; } - private Directory makeDirectories(UTF8String parent) { - assert !parent.isEmpty() : "non empty parent expected"; + private Resource newResource(Directory parent, ImageLocation loc) { + Resource res = Resource.create(parent, loc, imageFileAttributes()); + nodes.put(res.getName(), res); + return res; + } - int idx = parent.indexOf('/'); - assert idx != -1 : "invalid parent string"; - UTF8String name = ROOT.concat(parent.substring(0, idx)); - Directory top = (Directory) nodes.get(name); - if (top == null) { - top = newDirectory(rootDir, name); + private LinkNode newLinkNode(Directory dir, UTF8String name, Node link) { + LinkNode linkNode = LinkNode.create(dir, name, link); + nodes.put(linkNode.getName(), linkNode); + return linkNode; + } + + private List dirs(UTF8String parent) { + List splits = new ArrayList<>(); + + for (int i = 1; i < parent.length(); i++) { + if (parent.byteAt(i) == '/') { + splits.add(parent.substring(0, i)); + } } - Directory last = top; - while ((idx = parent.indexOf('/', idx + 1)) != -1) { - name = ROOT.concat(parent.substring(0, idx)); - Directory nextDir = (Directory) nodes.get(name); + + splits.add(parent); + + return splits; + } + + private Directory makeDirectories(UTF8String parent) { + Directory last = rootDir; + List dirs = dirs(parent); + + for (UTF8String dir : dirs) { + Directory nextDir = (Directory) nodes.get(dir); if (nextDir == null) { - nextDir = newDirectory(last, name); + nextDir = newDirectory(last, dir); } last = nextDir; } @@ -441,54 +668,6 @@ public class ImageReader extends BasicImageReader { return last; } - private void fillPackageModuleInfo() { - assert rootDir != null; - - packageMap.entrySet().stream().sorted((x, y)->x.getKey().compareTo(y.getKey())).forEach((entry) -> { - UTF8String moduleName = new UTF8String("/" + entry.getValue()); - UTF8String fullName = moduleName.concat(new UTF8String(entry.getKey() + "/")); - if (! nodes.containsKey(fullName)) { - Directory module = (Directory) nodes.get(moduleName); - assert module != null : "module directory missing " + moduleName; - module.setIsModuleDir(); - - // hide "packages.offsets" in module directories - Node packagesOffsets = nodes.get(moduleName.concat(ROOT, PACKAGES_OFFSETS)); - if (packagesOffsets != null) { - packagesOffsets.setIsHidden(); - } - - // package name without front '/' - UTF8String pkgName = new UTF8String(entry.getKey() + "/"); - int idx = -1; - Directory moduleSubDir = module; - while ((idx = pkgName.indexOf('/', idx + 1)) != -1) { - UTF8String subPkg = pkgName.substring(0, idx); - UTF8String moduleSubDirName = moduleName.concat(ROOT, subPkg); - Directory tmp = (Directory) nodes.get(moduleSubDirName); - if (tmp == null) { - moduleSubDir = newDirectory(moduleSubDir, moduleSubDirName); - } else { - moduleSubDir = tmp; - } - } - // copy pkgDir "resources" - Directory pkgDir = (Directory) nodes.get(ROOT.concat(pkgName.substring(0, pkgName.length() - 1))); - pkgDir.setIsTopLevelPackageDir(); - pkgDir.walk(n -> n.setIsHidden()); - for (Node child : pkgDir.getChildren()) { - if (child.isResource()) { - ImageLocation loc = child.getLocation(); - BasicFileAttributes imageFileAttrs = child.getFileAttributes(); - UTF8String rsName = moduleName.concat(child.getName()); - Resource rs = new Resource(moduleSubDir, rsName, loc, imageFileAttrs); - nodes.put(rs.getName(), rs); - } - } - } - }); - } - public byte[] getResource(Node node) throws IOException { if (node.isResource()) { return super.getResource(node.getLocation()); diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java new file mode 100644 index 00000000000..5f9a219a92f --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.ConcurrentHashMap; +import java.util.Map; + +/** + * Factory to get ImageReader + */ +public class ImageReaderFactory { + private ImageReaderFactory() {} + + private static final String JAVA_HOME = System.getProperty("java.home"); + private static final Path BOOT_MODULES_JIMAGE = + Paths.get(JAVA_HOME, "lib", "modules", "bootmodules.jimage"); + + private static final Map readers = new ConcurrentHashMap<>(); + + /** + * Returns an {@code ImageReader} to read from the given image file + */ + public static ImageReader get(Path jimage) throws IOException { + ImageReader reader = readers.get(jimage); + if (reader != null) { + return reader; + } + reader = ImageReader.open(jimage.toString()); + // potential race with other threads opening the same URL + ImageReader r = readers.putIfAbsent(jimage, reader); + if (r == null) { + return reader; + } else { + reader.close(); + return r; + } + } + + /** + * Returns the {@code ImageReader} to read the image file in this + * run-time image. + * + * @throws UncheckedIOException if an I/O error occurs + */ + public static ImageReader getImageReader() { + try { + return get(BOOT_MODULES_JIMAGE); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageResourcesTree.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageResourcesTree.java new file mode 100644 index 00000000000..60d4db3282c --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageResourcesTree.java @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * A class to build a sorted tree of Resource paths as a tree of ImageLocation. + * + */ +// XXX Public only due to the JImageTask / JImageTask code duplication +public final class ImageResourcesTree { + + private static final String MODULES = "modules"; + private static final String PACKAGES = "packages"; + public static final String MODULES_STRING = UTF8String.MODULES_STRING.toString(); + public static final String PACKAGES_STRING = UTF8String.PACKAGES_STRING.toString(); + + public static boolean isTreeInfoResource(String path) { + return path.startsWith(PACKAGES_STRING) || path.startsWith(MODULES_STRING); + } + + /** + * Path item tree node. + */ + private static final class Node { + + private final String name; + private final Map children = new TreeMap<>(); + private final Node parent; + private ImageLocationWriter loc; + + private Node(String name, Node parent) { + this.name = name; + this.parent = parent; + + if (parent != null) { + parent.children.put(name, this); + } + } + + public String getPath() { + if (parent == null) { + return "/"; + } + return buildPath(this); + } + + public String getName() { + return name; + } + + public Node getChildren(String name) { + Node item = children.get(name); + return item; + } + + private static String buildPath(Node item) { + if (item == null) { + return null; + } + String path = buildPath(item.parent); + if (path == null) { + return item.getName(); + } else { + return path + "/" + item.getName(); + } + } + } + + /** + * Tree of nodes. + */ + private static final class Tree { + + private final Map directAccess = new HashMap<>(); + private final List paths; + private final Node root; + private Node modules; + private Node packages; + + private Tree(List paths) { + this.paths = paths; + root = new Node("", null); + buildTree(); + } + + private void buildTree() { + modules = new Node(MODULES, root); + directAccess.put(modules.getPath(), modules); + + Map> moduleToPackage = new TreeMap<>(); + Map> packageToModule = new TreeMap<>(); + + for (String p : paths) { + if (!p.startsWith("/")) { + continue; + } + String[] split = p.split("/"); + Node current = modules; + String module = null; + for (int i = 0; i < split.length; i++) { + String s = split[i]; + if (!s.isEmpty()) { + if (module == null) { + module = s; + } + Node n = current.children.get(s); + if (n == null) { + n = new Node(s, current); + if (i == split.length - 1) { // Leaf + String pkg = toPackageName(n.parent); + if (pkg != null && !pkg.startsWith("META-INF")) { + Set pkgs = moduleToPackage.get(module); + if (pkgs == null) { + pkgs = new TreeSet<>(); + moduleToPackage.put(module, pkgs); + } + pkgs.add(pkg); + } + } else { // put only sub trees, no leaf + directAccess.put(n.getPath(), n); + String pkg = toPackageName(n); + if (pkg != null && !pkg.startsWith("META-INF")) { + Set mods = packageToModule.get(pkg); + if (mods == null) { + mods = new TreeSet<>(); + packageToModule.put(pkg, mods); + } + mods.add(module); + + } + } + } + current = n; + } + } + } + packages = new Node(PACKAGES, root); + directAccess.put(packages.getPath(), packages); + for (Map.Entry> entry : moduleToPackage.entrySet()) { + for (String pkg : entry.getValue()) { + Node pkgNode = new Node(pkg, packages); + directAccess.put(pkgNode.getPath(), pkgNode); + + Node modNode = new Node(entry.getKey(), pkgNode); + directAccess.put(modNode.getPath(), modNode); + } + } + for (Map.Entry> entry : packageToModule.entrySet()) { + Node pkgNode = new Node(entry.getKey(), packages); + directAccess.put(pkgNode.getPath(), pkgNode); + for (String module : entry.getValue()) { + Node modNode = new Node(module, pkgNode); + directAccess.put(modNode.getPath(), modNode); + } + } + } + + public String toResourceName(Node node) { + if (!node.children.isEmpty()) { + throw new RuntimeException("Node is not a resource"); + } + return removeRadical(node); + } + + public String getModule(Node node) { + if (node.parent == null || node.getName().equals(MODULES) || + node.getName().startsWith(PACKAGES)) { + return null; + } + String path = removeRadical(node); + // "/xxx/..."; + path = path.substring(1); + int i = path.indexOf("/"); + if (i == -1) { + return path; + } else { + return path.substring(0, i); + } + } + + public String toPackageName(Node node) { + if (node.parent == null) { + return null; + } + String path = removeRadical(node.getPath(), "/" + MODULES + "/"); + String module = getModule(node); + if (path.equals(module)) { + return null; + } + String pkg = removeRadical(path, module + "/"); + return pkg.replaceAll("/", "."); + } + + public String removeRadical(Node node) { + String s = node.getPath(); + return removeRadical(node.getPath(), "/" + MODULES); + } + + private String removeRadical(String path, String str) { + return path.substring(str.length()); + } + + public Node getRoot() { + return root; + } + + public Map getMap() { + return directAccess; + } + + private boolean isPackageNode(Node node) { + if (!node.children.isEmpty()) { + throw new RuntimeException("Node is not a package"); + } + return node.getPath().startsWith("/" + PACKAGES); + } + } + + private static final class LocationsAdder { + + private long offset; + private final List content = new ArrayList<>(); + private final BasicImageWriter writer; + private final Tree tree; + + LocationsAdder(Tree tree, long offset, BasicImageWriter writer) { + this.tree = tree; + this.offset = offset; + this.writer = writer; + addLocations(tree.getRoot()); + } + + private int addLocations(Node current) { + int[] ret = new int[current.children.size()]; + int i = 0; + for (java.util.Map.Entry entry : current.children.entrySet()) { + ret[i] = addLocations(entry.getValue()); + i += 1; + } + if (current != tree.getRoot() && (ret.length > 0 || tree.isPackageNode(current))) { + int size = ret.length * 4; + writer.addLocation(current.getPath(), offset, 0, size); + offset += size; + } + return 0; + } + + private List computeContent() { + // Map used to associate Tree item with locations offset. + Map outLocations = new HashMap<>(); + for (ImageLocationWriter wr : writer.getLocations()) { + outLocations.put(wr.getFullNameString(), wr); + } + // Attach location to node + for (Map.Entry entry : outLocations.entrySet()) { + Node item = tree.getMap().get(entry.getKey()); + if (item != null) { + item.loc = entry.getValue(); + } + } + computeContent(tree.getRoot(), outLocations); + return content; + } + + private int computeContent(Node current, Map outLocations) { + int[] ret = new int[current.children.size()]; + int i = 0; + for (java.util.Map.Entry entry : current.children.entrySet()) { + ret[i] = computeContent(entry.getValue(), outLocations); + i += 1; + } + if (ret.length > 0) { + int size = ret.length * 4; + ByteBuffer buff = ByteBuffer.allocate(size); + buff.order(writer.getByteOrder()); + for (int val : ret) { + buff.putInt(val); + } + byte[] arr = buff.array(); + content.add(arr); + } else { + if (tree.isPackageNode(current)) { + current.loc = outLocations.get(current.getPath()); + } else { + String s = tree.toResourceName(current); + current.loc = outLocations.get(s); + } + } + return current == tree.getRoot() ? 0 : current.loc.getLocationOffset(); + } + } + + private final List paths; + private final LocationsAdder adder; + + public ImageResourcesTree(long offset, BasicImageWriter writer, List paths) { + this.paths = new ArrayList<>(); + this.paths.addAll(paths); + Collections.sort(this.paths); + Tree tree = new Tree(this.paths); + adder = new LocationsAdder(tree, offset, writer); + } + + public void addContent(DataOutputStream out) throws IOException { + List content = adder.computeContent(); + for (byte[] c : content) { + out.write(c, 0, c.length); + } + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java index 034e5b24224..dd7709c8ac7 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java @@ -72,7 +72,7 @@ class ImageStream { return this; } - private void ensure(int needs) { + void ensure(int needs) { assert 0 <= needs : "Negative needs"; if (needs > buffer.remaining()) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStrings.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStrings.java index 11cb106b5fe..d4470d999a1 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStrings.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStrings.java @@ -25,83 +25,8 @@ package jdk.internal.jimage; -import java.nio.ByteBuffer; -import java.util.HashMap; +interface ImageStrings { + public UTF8String get(int offset); -class ImageStrings { - private static final int NOT_FOUND = -1; - static final int EMPTY_OFFSET = 0; - - private final HashMap stringToOffsetMap; - private final ImageStream stream; - - ImageStrings() { - this.stringToOffsetMap = new HashMap<>(); - this.stream = new ImageStream(); - - // Reserve 0 offset for empty string. - int offset = addString(UTF8String.EMPTY_STRING); - assert offset == 0 : "Empty string not zero offset"; - // Reserve 1 offset for frequently used ".class". - addString(UTF8String.CLASS_STRING); - } - - ImageStrings(ImageStream stream) { - this.stringToOffsetMap = new HashMap<>(); - this.stream = stream; - } - - private int addString(final UTF8String string) { - int offset = stream.getPosition(); - string.writeTo(stream); - stream.put('\0'); - stringToOffsetMap.put(string, offset); - - return offset; - } - - int add(final UTF8String string) { - int offset = find(string); - - return offset == NOT_FOUND ? addString(string) : offset; - } - - int find(final UTF8String string) { - Integer offset = stringToOffsetMap.get(string); - - return offset != null ? offset : NOT_FOUND; - } - - UTF8String get(int offset) { - ByteBuffer buffer = stream.getBuffer(); - assert 0 <= offset && offset < buffer.capacity() : "String buffer offset out of range"; - int zero = NOT_FOUND; - for (int i = offset; i < buffer.capacity(); i++) { - if (buffer.get(i) == '\0') { - zero = i; - break; - } - } - assert zero != UTF8String.NOT_FOUND; - int length = zero - offset; - byte[] bytes = new byte[length]; - int mark = buffer.position(); - buffer.position(offset); - buffer.get(bytes); - buffer.position(mark); - - return new UTF8String(bytes, 0, length); - } - - ImageStream getStream() { - return stream; - } - - int getSize() { - return stream.getSize(); - } - - int getCount() { - return stringToOffsetMap.size(); - } + public int add(final UTF8String string); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/Resource.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java similarity index 60% rename from jdk/src/java.base/share/classes/jdk/internal/jimage/Resource.java rename to jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java index f1e4d8f0ffa..e4ee6c3d220 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/Resource.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java @@ -22,46 +22,23 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.internal.jimage; -/** - * Resource is a class or resource file. - */ -public class Resource { - private final String name; - private final long size; - private final long csize; +class ImageStringsReader implements ImageStrings { + private final BasicImageReader reader; - public Resource(String name, long size, long csize) { - this.name = name; - this.size = size; - this.csize = csize; - } - - /** - * Returns the name of this entry. - */ - public String name() { - return name; - } - - /** - * Returns the number of uncompressed bytes for this entry. - */ - public long size() { - return size; - } - - /** - * Returns the number of compressed bytes for this entry; 0 if - * uncompressed. - */ - public long csize() { - return csize; + ImageStringsReader(BasicImageReader reader) { + this.reader = reader; } @Override - public String toString() { - return String.format("%s uncompressed size %d compressed size %d", name, size, csize); + public UTF8String get(int offset) { + return reader.getUTF8String(offset); + } + + @Override + public int add(final UTF8String string) { + throw new InternalError("Can not add strings at runtime"); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStringsWriter.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStringsWriter.java new file mode 100644 index 00000000000..9c00f66a6e4 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStringsWriter.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.nio.ByteBuffer; +import java.util.HashMap; + +class ImageStringsWriter implements ImageStrings { + private static final int NOT_FOUND = -1; + static final int EMPTY_OFFSET = 0; + static final UTF8String CLASS_STRING = new UTF8String("class"); + + private final HashMap stringToOffsetMap; + private final ImageStream stream; + + ImageStringsWriter() { + this.stringToOffsetMap = new HashMap<>(); + this.stream = new ImageStream(); + + // Reserve 0 offset for empty string. + int offset = addString(UTF8String.EMPTY_STRING); + assert offset == 0 : "Empty string not zero offset"; + // Reserve 1 offset for frequently used ".class". + addString(CLASS_STRING); + } + + private int addString(final UTF8String string) { + int offset = stream.getPosition(); + string.writeTo(stream); + stream.put('\0'); + stringToOffsetMap.put(string, offset); + + return offset; + } + + @Override + public int add(final UTF8String string) { + int offset = find(string); + + return offset == NOT_FOUND ? addString(string) : offset; + } + + int find(final UTF8String string) { + Integer offset = stringToOffsetMap.get(string); + + return offset != null ? offset : NOT_FOUND; + } + + @Override + public UTF8String get(int offset) { + ByteBuffer buffer = stream.getBuffer(); + assert 0 <= offset && offset < buffer.capacity() : "String buffer offset out of range"; + int zero = NOT_FOUND; + for (int i = offset; i < buffer.capacity(); i++) { + if (buffer.get(i) == '\0') { + zero = i; + break; + } + } + assert zero != UTF8String.NOT_FOUND; + int length = zero - offset; + byte[] bytes = new byte[length]; + int mark = buffer.position(); + buffer.position(offset); + buffer.get(bytes); + buffer.position(mark); + + return new UTF8String(bytes, 0, length); + } + + ImageStream getStream() { + return stream; + } + + int getSize() { + return stream.getSize(); + } + + int getCount() { + return stringToOffsetMap.size(); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/PackageModuleMap.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageSubstrate.java similarity index 55% rename from jdk/src/java.base/share/classes/jdk/internal/jimage/PackageModuleMap.java rename to jdk/src/java.base/share/classes/jdk/internal/jimage/ImageSubstrate.java index 45e6d01bad6..9d5b09d2ba9 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/PackageModuleMap.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageSubstrate.java @@ -22,41 +22,24 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.internal.jimage; -import java.io.IOException; +import java.io.Closeable; import java.nio.ByteBuffer; -import java.nio.IntBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -// Utility to read module info from .jimage file. - -public final class PackageModuleMap { - private PackageModuleMap() {} - - public static final String MODULES_ENTRY = "module/modules.offsets"; - public static final String PACKAGES_ENTRY = "packages.offsets"; - - /* - * Returns a package-to-module map. - * - * The package name is in binary name format. - */ - static Map readFrom(ImageReader reader) throws IOException { - Map result = new HashMap<>(); - List moduleNames = reader.getNames(MODULES_ENTRY); - - for (String moduleName : moduleNames) { - List packageNames = reader.getNames(moduleName + "/" + PACKAGES_ENTRY); - - for (String packageName : packageNames) { - result.put(packageName, moduleName); - } - } - return result; - } +interface ImageSubstrate extends Closeable { + @Override + void close(); + boolean supportsDataBuffer(); + ByteBuffer getIndexBuffer(long offset, long size); + ByteBuffer getDataBuffer(long offset, long size); + boolean read(long offset, + ByteBuffer compressedBuffer, long compressedSize, + ByteBuffer uncompressedBuffer, long uncompressedSize); + boolean read(long offset, + ByteBuffer uncompressedBuffer, long uncompressedSize); + byte[] getStringBytes(int offset); + long[] getAttributes(int offset); + ImageLocation findLocation(UTF8String name, ImageStringsReader strings); + int[] attributeOffsets(); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/PReader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/PReader.java deleted file mode 100644 index eca0295548f..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/PReader.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * 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.jimage; - -import java.io.Closeable; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -/** - * Supports reading a file from given positions (offsets) in the file. - */ - -public abstract class PReader implements Closeable { - private final FileChannel fc; - - protected PReader(FileChannel fc) { - this.fc = fc; - } - - /** - * Returns the {@code FileChannel}. - */ - final FileChannel channel() { - return fc; - } - - /** - * Closes this {@code PReader} and the underlying file. - */ - @Override - public final void close() throws IOException { - fc.close(); - } - - /** - * Returns {@code true} if this {@code PReader} and the underlying file is - * open. - */ - public final boolean isOpen() { - return fc.isOpen(); - } - - /** - * Returns {@code len} bytes from a given position in the file. The bytes - * are returned as a byte array. - * - * @throws IOException if an I/O error occurs - */ - public abstract byte[] read(int len, long position) throws IOException; - - /** - * Opens the given file, returning a {@code PReader} to read from the file. - * - * @implNote Returns a {@code PReader} that supports concurrent pread operations - * if possible, otherwise a simple {@code PReader} that doesn't support - * concurrent operations. - */ - static PReader open(String file) throws IOException { - Class clazz; - try { - clazz = Class.forName("jdk.internal.jimage.concurrent.ConcurrentPReader"); - } catch (ClassNotFoundException e) { - return new SimplePReader(file); - } - try { - Constructor ctor = clazz.getConstructor(String.class); - return (PReader) ctor.newInstance(file); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - if (cause instanceof IOException) - throw (IOException) cause; - if (cause instanceof Error) - throw (Error) cause; - if (cause instanceof RuntimeException) - throw (RuntimeException) cause; - throw new Error(e); - } catch (NoSuchMethodException | IllegalAccessException | - InstantiationException e) { - throw new InternalError(e); - } - } -} - -/** - * Simple PReader implementation based on {@code RandomAccessFile}. - * - * @implNote This class cannot use FileChannel read methods to do the - * positional reads because FileChannel is interruptible. - */ -class SimplePReader extends PReader { - private final RandomAccessFile raf; - - private SimplePReader(RandomAccessFile raf) throws IOException { - super(raf.getChannel()); - this.raf = raf; - } - - SimplePReader(String file) throws IOException { - this(new RandomAccessFile(file, "r")); - } - - @Override - public byte[] read(int len, long position) throws IOException { - synchronized (this) { - byte[] bytes = new byte[len]; - raf.seek(position); - int n = raf.read(bytes); - if (n != len) - throw new InternalError("short read, not handled yet"); - return bytes; - } - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/PerfectHashBuilder.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/PerfectHashBuilder.java new file mode 100644 index 00000000000..005a58c76d9 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/PerfectHashBuilder.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class PerfectHashBuilder { + private final static int RETRY_LIMIT = 1000; + + private Class entryComponent; + private Class bucketComponent; + + private final Map> map = new LinkedHashMap<>(); + private int[] redirect; + private Entry[] order; + private int count = 0; + + @SuppressWarnings("EqualsAndHashcode") + public static class Entry { + private final UTF8String key; + private final E value; + + Entry() { + this("", null); + } + + Entry(String key, E value) { + this(new UTF8String(key), value); + } + + Entry(UTF8String key, E value) { + this.key = key; + this.value = value; + } + + UTF8String getKey() { + return key; + } + + E getValue() { + return value; + } + + int hashCode(int seed) { + return key.hashCode(seed); + } + + @Override + public int hashCode() { + return key.hashCode(); + } + } + + static class Bucket implements Comparable> { + final List> list = new ArrayList<>(); + + void add(Entry entry) { + list.add(entry); + } + + int getSize() { + return list.size(); + } + + List> getList() { + return list; + } + + Entry getFirst() { + assert !list.isEmpty() : "bucket should never be empty"; + return list.get(0); + } + + @Override + public int hashCode() { + return getFirst().hashCode(); + } + + @Override + @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") + public boolean equals(Object obj) { + return this == obj; + } + + @Override + public int compareTo(Bucket o) { + return o.getSize() - getSize(); + } + } + + public PerfectHashBuilder(Class entryComponent, Class bucketComponent) { + this.entryComponent = entryComponent; + this.bucketComponent = bucketComponent; + } + + public int getCount() { + return map.size(); + } + + public int[] getRedirect() { + return redirect; + } + + public Entry[] getOrder() { + return order; + } + + public Entry put(String key, E value) { + return put(new UTF8String(key), value); + } + + public Entry put(UTF8String key, E value) { + return put(new Entry<>(key, value)); + } + + public Entry put(Entry entry) { + Entry old = map.put(entry.key, entry); + + if (old == null) { + count++; + } + + return old; + } + + @SuppressWarnings("unchecked") + public void generate() { + boolean redo = count != 0; + while (redo) { + redo = false; + redirect = new int[count]; + order = (Entry[])Array.newInstance(entryComponent, count); + + Bucket[] sorted = createBuckets(); + int free = 0; + + for (Bucket bucket : sorted) { + if (bucket.getSize() != 1) { + if (!collidedEntries(bucket, count)) { + redo = true; + break; + } + } else { + for ( ; free < count && order[free] != null; free++) {} + + if (free >= count) { + redo = true; + break; + } + + order[free] = bucket.getFirst(); + redirect[bucket.hashCode() % count] = -1 - free; + free++; + } + } + + if (redo) { + count = (count + 1) | 1; + } + } + } + + @SuppressWarnings("unchecked") + private Bucket[] createBuckets() { + Bucket[] buckets = (Bucket[])Array.newInstance(bucketComponent, count); + + map.values().stream().forEach((entry) -> { + int index = entry.hashCode() % count; + Bucket bucket = buckets[index]; + + if (bucket == null) { + buckets[index] = bucket = new Bucket<>(); + } + + bucket.add(entry); + }); + + Bucket[] sorted = Arrays.asList(buckets).stream() + .filter((bucket) -> (bucket != null)) + .sorted() + .toArray((length) -> { + return (Bucket[])Array.newInstance(bucketComponent, length); + }); + + return sorted; + } + + private boolean collidedEntries(Bucket bucket, int count) { + List undo = new ArrayList<>(); + int seed = UTF8String.HASH_MULTIPLIER + 1; + int retry = 0; + + redo: + while (true) { + for (Entry entry : bucket.getList()) { + int index = entry.hashCode(seed) % count; + if (order[index] != null) { + if (++retry > RETRY_LIMIT) { + return false; + } + + undo.stream().forEach((i) -> { + order[i] = null; + }); + + undo.clear(); + seed++; + + if (seed == 0) { + seed = 1; + } + + continue redo; + } + + order[index] = entry; + undo.add(index); + } + + redirect[bucket.hashCode() % count] = seed; + + break; + } + + return true; + } + } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePool.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePool.java new file mode 100644 index 00000000000..89c1012f65c --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePool.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import jdk.internal.jimage.decompressor.CompressedResourceHeader; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * Pool of resources. This class contain the content of a jimage file in the + * matter of Resource. + */ +public interface ResourcePool { + + /** + * Resources visitor + */ + public interface Visitor { + + /** + * Called for each visited Resource. + * + * @param resource The resource to deal with. + * @param order Byte order + * @param strings + * @return A resource or null if the passed resource is to be removed + * from the jimage. + * @throws Exception + */ + public Resource visit(Resource resource, ByteOrder order, + StringTable strings) throws Exception; + } + + /** + * A JImage Resource. Fully identified by its path. + */ + public static class Resource { + + private final String path; + private final ByteBuffer content; + + private final String module; + + public Resource(String path, ByteBuffer content) { + Objects.requireNonNull(path); + Objects.requireNonNull(content); + this.path = path; + this.content = content.asReadOnlyBuffer(); + String[] split = ImageFileCreator.splitPath(path); + module = split[0]; + } + + public String getPath() { + return path; + } + + public String getModule() { + return module; + } + + /** + * The resource content. + * + * @return A read only buffer. + */ + public ByteBuffer getContent() { + return content; + } + + public int getLength() { + return content.limit(); + } + + public byte[] getByteArray() { + content.rewind(); + byte[] array = new byte[content.remaining()]; + content.get(array); + return array; + } + + @Override + public String toString() { + return getPath(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Resource)) { + return false; + } + Resource res = (Resource) obj; + return res.path.equals(path); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 53 * hash + Objects.hashCode(this.path); + return hash; + } + } + + /** + * A resource that has been compressed. + */ + public static final class CompressedResource extends Resource { + + private final long uncompressed_size; + + private CompressedResource(String path, ByteBuffer content, + long uncompressed_size) { + super(path, content); + this.uncompressed_size = uncompressed_size; + } + + public long getUncompressedSize() { + return uncompressed_size; + } + + public static CompressedResource newCompressedResource(Resource original, + ByteBuffer compressed, + String plugin, String pluginConfig, StringTable strings, + ByteOrder order) throws Exception { + Objects.requireNonNull(original); + Objects.requireNonNull(compressed); + Objects.requireNonNull(plugin); + + boolean isTerminal = !(original instanceof CompressedResource); + long uncompressed_size = original.getLength(); + if (original instanceof CompressedResource) { + CompressedResource comp = (CompressedResource) original; + uncompressed_size = comp.getUncompressedSize(); + } + int nameOffset = strings.addString(plugin); + int configOffset = -1; + if (pluginConfig != null) { + configOffset = strings.addString(plugin); + } + CompressedResourceHeader rh = + new CompressedResourceHeader(compressed.limit(), original.getLength(), + nameOffset, configOffset, isTerminal); + // Merge header with content; + byte[] h = rh.getBytes(order); + ByteBuffer bb = ByteBuffer.allocate(compressed.limit() + h.length); + bb.order(order); + bb.put(h); + bb.put(compressed); + ByteBuffer contentWithHeader = ByteBuffer.wrap(bb.array()); + + CompressedResource compressedResource = + new CompressedResource(original.getPath(), + contentWithHeader, uncompressed_size); + return compressedResource; + } + } + + /** + * Read only state. + * + * @return true if readonly false otherwise. + */ + public boolean isReadOnly(); + + /** + * The byte order + * + * @return + */ + public ByteOrder getByteOrder(); + + /** + * Add a resource. + * + * @param resource The Resource to add. + * @throws java.lang.Exception If the pool is read only. + */ + public void addResource(Resource resource) throws Exception; + + /** + * Check if a resource is contained in the pool. + * + * @param res The resource to check. + * @return true if res is contained, false otherwise. + */ + public boolean contains(Resource res); + + /** + * Get all resources contained in this pool instance. + * + * @return The collection of resources; + */ + public Collection getResources(); + + /** + * Get the resource for the passed path. + * + * @param path A resource path + * @return A Resource instance or null if the resource is not found + */ + public Resource getResource(String path); + + /** + * The Image modules. It is computed based on the resources contained by + * this ResourcePool instance. + * + * @return The Image Modules. + */ + public Map> getModulePackages(); + + /** + * Check if this pool contains some resources. + * + * @return True if contains some resources. + */ + public boolean isEmpty(); + + /** + * Visit the resources contained in this ResourcePool. + * + * @param visitor The visitor + * @param output The pool to store resources. + * @param strings + * @throws Exception + */ + public void visit(Visitor visitor, ResourcePool output, StringTable strings) + throws Exception; + + public void addTransformedResource(Resource original, ByteBuffer transformed) + throws Exception; +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePoolImpl.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePoolImpl.java new file mode 100644 index 00000000000..b54ff09411a --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePoolImpl.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * Pool of resources. This class contain the content of a jimage file in the + * matter of Resource. + */ +public class ResourcePoolImpl implements ResourcePool { + + private final Map resources = new LinkedHashMap<>(); + + private final ByteOrder order; + private boolean isReadOnly; + + public ResourcePoolImpl(ByteOrder order) { + Objects.requireNonNull(order); + this.order = order; + } + + /** + * Make this Resources instance read-only. No resource can be added. + */ + public void setReadOnly() { + isReadOnly = true; + } + + /** + * Read only state. + * + * @return true if readonly false otherwise. + */ + @Override + public boolean isReadOnly() { + return isReadOnly; + } + + /** + * The byte order + * + * @return + */ + @Override + public ByteOrder getByteOrder() { + return order; + } + + /** + * Add a resource. + * + * @param resource The Resource to add. + * @throws java.lang.Exception If the pool is read only. + */ + @Override + public void addResource(Resource resource) throws Exception { + if (isReadOnly()) { + throw new Exception("pool is readonly"); + } + Objects.requireNonNull(resource); + if (resources.get(resource.getPath()) != null) { + throw new Exception("Resource" + resource.getPath() + + " already present"); + } + resources.put(resource.getPath(), resource); + } + + /** + * Check if a resource is contained in the pool. + * + * @param res The resource to check. + * @return true if res is contained, false otherwise. + */ + @Override + public boolean contains(Resource res) { + Objects.requireNonNull(res); + try { + getResource(res.getPath()); + return true; + } catch (Exception ex) { + return false; + } + } + + /** + * Get all resources contained in this pool instance. + * + * @return The collection of resources; + */ + @Override + public Collection getResources() { + return Collections.unmodifiableCollection(resources.values()); + } + +/** + * Get the resource for the passed path. + * + * @param path A resource path + * @return A Resource instance or null if the resource is not found + */ + @Override + public Resource getResource(String path) { + Objects.requireNonNull(path); + return resources.get(path); + } + + /** + * The Image modules. It is computed based on the resources contained by + * this ResourcePool instance. + * + * @return The Image Modules. + */ + @Override + public Map> getModulePackages() { + Map> moduleToPackage = new LinkedHashMap<>(); + retrieveModulesPackages(moduleToPackage); + return moduleToPackage; + } + + /** + * Check if this pool contains some resources. + * + * @return True if contains some resources. + */ + @Override + public boolean isEmpty() { + return resources.isEmpty(); + } + + /** + * Visit the resources contained in this ResourcePool. + * + * @param visitor The visitor + * @param strings + * @throws Exception + */ + @Override + public void visit(Visitor visitor, ResourcePool output, StringTable strings) + throws Exception { + for (Resource resource : getResources()) { + Resource res = visitor.visit(resource, order, strings); + if (res != null) { + output.addResource(res); + } + } + } + + @Override + public void addTransformedResource(Resource original, ByteBuffer transformed) + throws Exception { + if (isReadOnly()) { + throw new Exception("Pool is readonly"); + } + Objects.requireNonNull(original); + Objects.requireNonNull(transformed); + if (resources.get(original.getPath()) != null) { + throw new Exception("Resource already present"); + } + Resource res = new Resource(original.getPath(), transformed); + addResource(res); + } + + private void retrieveModulesPackages(Map> moduleToPackage) { + for (Resource res : resources.values()) { + Set pkgs = moduleToPackage.get(res.getModule()); + if (pkgs == null) { + pkgs = new HashSet<>(); + moduleToPackage.put(res.getModule(), pkgs); + } + // Module metadata only contains packages with resource files + if (ImageFileCreator.isResourcePackage(res.getPath())) { + String[] split = ImageFileCreator.splitPath(res.getPath()); + String pkg = split[1]; + if (pkg != null && !pkg.isEmpty()) { + pkgs.add(pkg); + } + } + } + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/StringTable.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/StringTable.java new file mode 100644 index 00000000000..a5f7967d9ea --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/StringTable.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.jimage; + +/** +* Added strings are stored in the jimage strings table. +*/ +public interface StringTable { + /** + * Add a string to the jimage strings table. + * @param str The string to add. + * @return a String identifier. + */ + public int addString(String str); + + /** + * Retrieve a string from the passed id. + * @param id The string id. + * @return The string referenced by the passed id. + */ + public String getString(int id); +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/UTF8String.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/UTF8String.java index 893a986df23..531c0ba3de3 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/UTF8String.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/UTF8String.java @@ -29,14 +29,18 @@ import java.nio.charset.Charset; import java.util.Arrays; public final class UTF8String implements CharSequence { - // Same as StandardCharsets.UTF_8 without loading all of the standard charsets static final Charset UTF_8 = Charset.forName("UTF-8"); static final int NOT_FOUND = -1; static final int HASH_MULTIPLIER = 0x01000193; - static final UTF8String EMPTY_STRING = new UTF8String(""); - static final UTF8String CLASS_STRING = new UTF8String(".class"); + static final UTF8String EMPTY_STRING = new UTF8String(""); + static final UTF8String SLASH_STRING = new UTF8String("/"); + static final UTF8String DOT_STRING = new UTF8String("."); + + // TODO This strings are implementation specific and should be defined elsewhere. + static final UTF8String MODULES_STRING = new UTF8String("/modules"); + static final UTF8String PACKAGES_STRING = new UTF8String("/packages"); final byte[] bytes; final int offset; @@ -160,8 +164,8 @@ public final class UTF8String implements CharSequence { return seed & 0x7FFFFFFF; } - int hashCode(int base) { - return hashCode(base, bytes, offset, count); + int hashCode(int seed) { + return hashCode(seed, bytes, offset, count); } @Override @@ -186,7 +190,7 @@ public final class UTF8String implements CharSequence { return equals(this, (UTF8String)obj); } - private static boolean equals(UTF8String a, UTF8String b) { + public static boolean equals(UTF8String a, UTF8String b) { if (a == b) { return true; } @@ -211,6 +215,10 @@ public final class UTF8String implements CharSequence { return true; } + public byte[] getBytesCopy() { + return Arrays.copyOfRange(bytes, offset, offset + count); + } + byte[] getBytes() { if (offset != 0 || bytes.length != count) { return Arrays.copyOfRange(bytes, offset, offset + count); @@ -232,33 +240,11 @@ public final class UTF8String implements CharSequence { public char charAt(int index) { int ch = byteAt(index); - return (ch & 0x80) != 0 ? (char)ch : '\0'; + return (ch & 0x80) == 0 ? (char)ch : '\0'; } @Override public CharSequence subSequence(int start, int end) { return (CharSequence)substring(start, end - start); } - - static UTF8String match(UTF8String a, UTF8String b) { - int aCount = a.count; - int bCount = b.count; - - if (aCount < bCount) { - return null; - } - - byte[] aBytes = a.bytes; - byte[] bBytes = b.bytes; - int aOffset = a.offset; - int bOffset = b.offset; - - for (int i = 0; i < bCount; i++) { - if (aBytes[aOffset + i] != bBytes[bOffset + i]) { - return null; - } - } - - return new UTF8String(aBytes, aOffset + bCount, aCount - bCount); - } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/concurrent/ConcurrentPReader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/concurrent/ConcurrentPReader.java deleted file mode 100644 index 9904bed21bf..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/concurrent/ConcurrentPReader.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * 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.jimage.concurrent; - -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.IOException; - -import jdk.internal.jimage.PReader; - -import sun.misc.Unsafe; - -/** - * A PReader implementation that supports concurrent pread operations. - */ -public class ConcurrentPReader extends PReader { - - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); - private static final long BA_OFFSET = (long) UNSAFE.arrayBaseOffset(byte[].class); - - /** - * A temporary buffer that is cached on a per-thread basis. - */ - private static class TemporaryBuffer { - static final ThreadLocal CACHED_BUFFER = - new ThreadLocal() { - @Override - protected TemporaryBuffer initialValue() { return null; } - }; - - static final TemporaryBuffer NOT_AVAILABLE = new TemporaryBuffer(0L, 0); - - final long address; - final int size; - - TemporaryBuffer(long address, int size) { - this.address = address; - this.size = size; - } - - long address() { return address; } - int size() { return size; } - - /** - * Returns the {@code TemporaryBuffer} for the current thread. The buffer - * is guaranteed to be of at least the given size. Returns {@code null} - * if a buffer cannot be cached for this thread. - */ - static TemporaryBuffer get(int len) { - TemporaryBuffer buffer = CACHED_BUFFER.get(); - - // cached buffer large enough? - if (buffer != null && buffer.size() >= len) { - return buffer; - } - - // if this is an InnocuousThread then don't return anything - if (buffer == NOT_AVAILABLE) - return null; - - if (buffer != null) { - // replace buffer in cache with a larger buffer - long originalAddress = buffer.address(); - long address = UNSAFE.allocateMemory(len); - buffer = new TemporaryBuffer(address, len); - CACHED_BUFFER.set(buffer); - UNSAFE.freeMemory(originalAddress); - } else { - // first usage. - if (Thread.currentThread() instanceof sun.misc.InnocuousThread) { - buffer = NOT_AVAILABLE; - } else { - long address = UNSAFE.allocateMemory(len); - buffer = new TemporaryBuffer(address, len); - } - CACHED_BUFFER.set(buffer); - } - return buffer; - } - } - - private final FileDescriptor fd; - - private ConcurrentPReader(FileInputStream fis) throws IOException { - super(fis.getChannel()); - this.fd = fis.getFD(); - } - - public ConcurrentPReader(String file) throws IOException { - this(new FileInputStream(file)); - } - - @Override - public byte[] read(int len, long position) throws IOException { - // need a temporary area of memory to read into - TemporaryBuffer buffer = TemporaryBuffer.get(len); - long address; - if (buffer == null) { - address = UNSAFE.allocateMemory(len); - } else { - address = buffer.address(); - } - try { - int n = pread(fd, address, len, position); - if (n != len) - throw new InternalError("short read, not handled yet"); - byte[] result = new byte[n]; - UNSAFE.copyMemory(null, address, result, BA_OFFSET, len); - return result; - } finally { - if (buffer == null) { - UNSAFE.freeMemory(address); - } - } - } - - private static native int pread(FileDescriptor fd, long address, int len, long pos) - throws IOException; - - private static native void initIDs(); - - static { - System.loadLibrary("java"); - initIDs(); - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressedResourceHeader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressedResourceHeader.java new file mode 100644 index 00000000000..66afd336b66 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressedResourceHeader.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.jimage.decompressor; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Objects; +import jdk.internal.jimage.decompressor.ResourceDecompressor.StringsProvider; + +/** + * + * A resource header for compressed resource. This class is handled internally, + * you don't have to add header to the resource, headers are added automatically + * for compressed resources. + */ +public final class CompressedResourceHeader { + + private static final int SIZE = 21; + public static final int MAGIC = 0xCAFEFAFA; + private final int uncompressedSize; + private final int compressedSize; + private final int decompressorNameOffset; + private final int contentOffset; + private final boolean isTerminal; + + public CompressedResourceHeader(int compressedSize, + int uncompressedSize, int decompressorNameOffset, int contentOffset, + boolean isTerminal) { + this.compressedSize = compressedSize; + this.uncompressedSize = uncompressedSize; + this.decompressorNameOffset = decompressorNameOffset; + this.contentOffset = contentOffset; + this.isTerminal = isTerminal; + } + + public boolean isTerminal() { + return isTerminal; + } + + public int getDecompressorNameOffset() { + return decompressorNameOffset; + } + + public int getContentOffset() { + return contentOffset; + } + + public String getStoredContent(StringsProvider provider) { + Objects.nonNull(provider); + if(contentOffset == -1) { + return null; + } + return provider.getString(contentOffset); + } + + public int getUncompressedSize() { + return uncompressedSize; + } + + public int getResourceSize() { + return compressedSize; + } + + public byte[] getBytes(ByteOrder order) { + Objects.requireNonNull(order); + ByteBuffer buffer = ByteBuffer.allocate(SIZE); + buffer.order(order); + buffer.putInt(MAGIC); + buffer.putInt(compressedSize); + buffer.putInt(uncompressedSize); + buffer.putInt(decompressorNameOffset); + buffer.putInt(contentOffset); + buffer.put(isTerminal ? (byte)1 : (byte)0); + return buffer.array(); + } + + public static int getSize() { + return SIZE; + } + + public static CompressedResourceHeader readFromResource(ByteOrder order, + byte[] resource) { + Objects.requireNonNull(order); + Objects.requireNonNull(resource); + if (resource.length < getSize()) { + return null; + } + ByteBuffer buffer = ByteBuffer.wrap(resource, 0, SIZE); + buffer.order(order); + int magic = buffer.getInt(); + if(magic != MAGIC) { + return null; + } + int size = buffer.getInt(); + int uncompressedSize = buffer.getInt(); + int decompressorNameOffset = buffer.getInt(); + int contentIndex = buffer.getInt(); + byte isTerminal = buffer.get(); + return new CompressedResourceHeader(size, uncompressedSize, + decompressorNameOffset, contentIndex, isTerminal == 1); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/Decompressor.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/Decompressor.java new file mode 100644 index 00000000000..0c640e0e0da --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/Decompressor.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.jimage.decompressor; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteOrder; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import jdk.internal.jimage.decompressor.ResourceDecompressor.StringsProvider; + +/** + * Entry point to decompress resources. + */ +public final class Decompressor { + + private final Map pluginsCache = new HashMap<>(); + + public Decompressor() { + } + + /** + * Decompress a resource. + * @param order Byte order. + * @param provider Strings provider + * @param content The resource content to uncompress. + * @return A fully uncompressed resource. + * @throws IOException + */ + public byte[] decompressResource(ByteOrder order, StringsProvider provider, + byte[] content) throws IOException { + Objects.requireNonNull(order); + Objects.requireNonNull(provider); + Objects.requireNonNull(content); + CompressedResourceHeader header; + do { + header = CompressedResourceHeader.readFromResource(order, content); + if (header != null) { + ResourceDecompressor decompressor = + pluginsCache.get(header.getDecompressorNameOffset()); + if (decompressor == null) { + String pluginName = + provider.getString(header.getDecompressorNameOffset()); + if (pluginName == null) { + throw new IOException("Plugin name not found"); + } + String storedContent = header.getStoredContent(provider); + Properties props = new Properties(); + if (storedContent != null) { + try (ByteArrayInputStream stream = + new ByteArrayInputStream(storedContent.getBytes());) { + props.loadFromXML(stream); + } + } + decompressor = ResourceDecompressorRepository. + newResourceDecompressor(props, pluginName); + if (decompressor == null) { + throw new IOException("Plugin not found: " + pluginName); + } + + pluginsCache.put(header.getDecompressorNameOffset(), decompressor); + } + try { + content = decompressor.decompress(provider, content, + CompressedResourceHeader.getSize(), header.getUncompressedSize()); + } catch (Exception ex) { + throw new IOException(ex); + } + } + } while (header != null); + return content; + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressor.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressor.java new file mode 100644 index 00000000000..1e1e99e3247 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressor.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.jimage.decompressor; + +/** + * + * JImage Decompressor. + */ +public interface ResourceDecompressor { + + public interface StringsProvider { + public String getString(int offset); + } + /** + * Decompressor unique name. + * @return The decompressor name. + */ + public String getName(); + + /** + * Decompress a resource. + * @param strings The String provider + * @param content The resource content + * @param offset Resource content offset + * @param originalSize Uncompressed size + * @return Uncompressed resource + * @throws Exception + */ + public byte[] decompress(StringsProvider strings, byte[] content, int offset, + int originalSize) throws Exception; +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java new file mode 100644 index 00000000000..4a517a06546 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.jimage.decompressor; + +import java.io.IOException; +import java.util.Properties; + +/** + * + * JImage Resource Decompressor factory + */ +public abstract class ResourceDecompressorFactory { + private final String name; + private final String description; + private final String arguments; + + protected ResourceDecompressorFactory(String name, String description, + String arguments) { + this.name = name; + this.description = description; + this.arguments = arguments; + } + + /** + * The Factory name. + * @return The name. + */ + public String getName() { + return name; + } + + /** + * The Factory description. + * @return The description. + */ + public String getDescription() { + return description; + } + + /** + * The Factory arguments description. + * @return The arguments description. + */ + public String getArgumentsDescription() { + return arguments; + } + + /** + * To build a new decompressor. + * @param properties Contains configuration. + * @return A new decompressor. + * @throws IOException + */ + public abstract ResourceDecompressor newDecompressor(Properties properties) + throws IOException; + +} + diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java new file mode 100644 index 00000000000..90800351c9f --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.jimage.decompressor; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * + * JImage Decompressors. All decompressors must be registered in the static + * initializer of this class. + */ +public final class ResourceDecompressorRepository { + + private ResourceDecompressorRepository() { + } + + private static final Map factories = new HashMap<>(); + + static { + registerReaderProvider(new ZipDecompressorFactory()); + } + + /** + * Build a new decompressor for the passed name. + * @param properties Contains plugin configuration. + * @param name The plugin name to build. + * @return A decompressor or null if not found + * @throws IOException + */ + public static ResourceDecompressor newResourceDecompressor(Properties properties, + String name) throws IOException { + + ResourceDecompressorFactory fact = factories.get(name); + if (fact != null) { + return fact.newDecompressor(properties); + } + return null; + } + + private static void registerReaderProvider(ResourceDecompressorFactory factory) { + factories.put(factory.getName(), factory); + } + + +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java new file mode 100644 index 00000000000..18aeb9ef7a0 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.jimage.decompressor; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.DataFormatException; +import java.util.zip.Inflater; + +/** + * + * ZIP Decompressor + */ +final class ZipDecompressor implements ResourceDecompressor { + + @Override + public String getName() { + return ZipDecompressorFactory.NAME; + } + + static byte[] decompress(byte[] bytesIn, int offset) { + Inflater inflater = new Inflater(); + inflater.setInput(bytesIn, offset, bytesIn.length - offset); + ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length - offset); + byte[] buffer = new byte[1024]; + + while (!inflater.finished()) { + int count; + + try { + count = inflater.inflate(buffer); + } catch (DataFormatException ex) { + return null; + } + + stream.write(buffer, 0, count); + } + + try { + stream.close(); + } catch (IOException ex) { + return null; + } + + byte[] bytesOut = stream.toByteArray(); + inflater.end(); + + return bytesOut; + } + + @Override + public byte[] decompress(StringsProvider reader, byte[] content, int offset, + int originalSize) throws Exception { + byte[] decompressed = decompress(content, offset); + return decompressed; + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java new file mode 100644 index 00000000000..cbdbcc67e79 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.jimage.decompressor; + +import java.io.IOException; +import java.util.Properties; + +/** + * + * ZIP decompressor factory + */ +public final class ZipDecompressorFactory extends ResourceDecompressorFactory { + public static final String NAME = "zip"; + public ZipDecompressorFactory() { + super(NAME, "ZIP Decompression", null); + } + + @Override + public ResourceDecompressor newDecompressor(Properties properties) + throws IOException { + return new ZipDecompressor(); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java index 1ef500d95f9..1a870fa6d95 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java @@ -51,7 +51,7 @@ final class JrtDirectoryStream implements DirectoryStream { this.jrtfs = jrtPath.getFileSystem(); this.path = jrtPath.getResolvedPath(); // sanity check - if (!jrtfs.isDirectory(path)) + if (!jrtfs.isDirectory(path, true)) throw new NotDirectoryException(jrtPath.toString()); // absolute path and does not have funky chars in front like /./java.base diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java index cdcde909fe3..93b88f7fea8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java @@ -25,6 +25,7 @@ package jdk.internal.jrtfs; +import java.nio.file.LinkOption; import java.nio.file.attribute.*; import java.io.IOException; import java.util.LinkedHashMap; @@ -48,30 +49,32 @@ final class JrtFileAttributeView implements BasicFileAttributeView private final JrtPath path; private final boolean isJrtView; + private final LinkOption[] options; - private JrtFileAttributeView(JrtPath path, boolean isJrtView) { + private JrtFileAttributeView(JrtPath path, boolean isJrtView, LinkOption... options) { this.path = path; this.isJrtView = isJrtView; + this.options = options; } @SuppressWarnings("unchecked") // Cast to V - static V get(JrtPath path, Class type) { + static V get(JrtPath path, Class type, LinkOption... options) { if (type == null) throw new NullPointerException(); if (type == BasicFileAttributeView.class) - return (V)new JrtFileAttributeView(path, false); + return (V)new JrtFileAttributeView(path, false, options); if (type == JrtFileAttributeView.class) - return (V)new JrtFileAttributeView(path, true); + return (V)new JrtFileAttributeView(path, true, options); return null; } - static JrtFileAttributeView get(JrtPath path, String type) { + static JrtFileAttributeView get(JrtPath path, String type, LinkOption... options) { if (type == null) throw new NullPointerException(); if (type.equals("basic")) - return new JrtFileAttributeView(path, false); + return new JrtFileAttributeView(path, false, options); if (type.equals("jjrt")) - return new JrtFileAttributeView(path, true); + return new JrtFileAttributeView(path, true, options); return null; } @@ -83,7 +86,7 @@ final class JrtFileAttributeView implements BasicFileAttributeView @Override public JrtFileAttributes readAttributes() throws IOException { - return path.getAttributes(); + return path.getAttributes(options); } @Override diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java index bfebbebcb31..f09dec55059 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java @@ -76,12 +76,12 @@ final class JrtFileAttributes implements BasicFileAttributes @Override public boolean isSymbolicLink() { - return false; + return node.isLink(); } @Override public Object fileKey() { - return null; + return node.resolveLink(true); } ///////// jrt entry attributes /////////// diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java index 3766e808f8a..641428be03d 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java @@ -31,9 +31,9 @@ import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.charset.Charset; -import java.nio.file.AccessMode; import java.nio.file.ClosedFileSystemException; import java.nio.file.CopyOption; +import java.nio.file.LinkOption; import java.nio.file.FileStore; import java.nio.file.FileSystem; import java.nio.file.FileSystemException; @@ -45,16 +45,13 @@ import java.nio.file.OpenOption; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.ReadOnlyFileSystemException; -import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.nio.file.WatchService; import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.FileTime; import java.nio.file.attribute.UserPrincipalLookupService; import java.nio.file.spi.FileSystemProvider; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; +import java.util.concurrent.ConcurrentHashMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -63,8 +60,9 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.regex.Pattern; -import java.util.stream.Collectors; +import static java.util.stream.Collectors.toList; import jdk.internal.jimage.ImageReader; import jdk.internal.jimage.ImageReader.Node; import jdk.internal.jimage.UTF8String; @@ -74,6 +72,7 @@ import jdk.internal.jimage.UTF8String; */ class JrtFileSystem extends FileSystem { private static final Charset UTF_8 = Charset.forName("UTF-8"); + private final JrtFileSystemProvider provider; // System image readers private ImageReader bootImage; @@ -109,7 +108,8 @@ class JrtFileSystem extends FileSystem { this.extImage = openImage(SystemImages.extImagePath); this.appImage = openImage(SystemImages.appImagePath); - rootPath = new JrtPath(this, new byte[]{'/'}); + byte[] root = new byte[] { '/' }; + rootPath = new JrtPath(this, root); isOpen = true; } @@ -149,12 +149,12 @@ class JrtFileSystem extends FileSystem { synchronized(this) { isOpen = false; - // close all image readers and null out + // close all image reader and null out bootImage.close(); - extImage.close(); - appImage.close(); bootImage = null; + extImage.close(); extImage = null; + appImage.close(); appImage = null; } } @@ -289,21 +289,52 @@ class JrtFileSystem extends FileSystem { } } - private NodeAndImage findNode(byte[] path) throws IOException { - ImageReader image = bootImage; + private NodeAndImage lookup(byte[] path) { Node node = bootImage.findNode(path); + ImageReader image = bootImage; if (node == null) { - image = extImage; node = extImage.findNode(path); + image = extImage; } if (node == null) { - image = appImage; node = appImage.findNode(path); + image = appImage; } - if (node == null || node.isHidden()) { - throw new NoSuchFileException(getString(path)); + return node != null? new NodeAndImage(node, image) : null; + } + + private NodeAndImage lookupSymbolic(byte[] path) { + for (int i = 1; i < path.length; i++) { + if (path[i] == (byte)'/') { + byte[] prefix = Arrays.copyOfRange(path, 0, i); + NodeAndImage ni = lookup(prefix); + if (ni == null) { + break; + } + + if (ni.node.isLink()) { + Node link = ni.node.resolveLink(true); + // resolved symbolic path concatenated to the rest of the path + UTF8String resPath = link.getName().concat(new UTF8String(path, i)); + byte[] resPathBytes = resPath.getBytesCopy(); + ni = lookup(resPathBytes); + return ni != null? ni : lookupSymbolic(resPathBytes); + } + } } - return new NodeAndImage(node, image); + + return null; + } + + private NodeAndImage findNode(byte[] path) throws IOException { + NodeAndImage ni = lookup(path); + if (ni == null) { + ni = lookupSymbolic(path); + if (ni == null) { + throw new NoSuchFileException(getString(path)); + } + } + return ni; } private NodeAndImage checkNode(byte[] path) throws IOException { @@ -321,10 +352,28 @@ class JrtFileSystem extends FileSystem { return ni; } + static boolean followLinks(LinkOption... options) { + if (options != null) { + for (LinkOption lo : options) { + if (lo == LinkOption.NOFOLLOW_LINKS) { + return false; + } else if (lo == null) { + throw new NullPointerException(); + } else { + throw new AssertionError("should not reach here"); + } + } + } + return true; + } + // package private helpers - JrtFileAttributes getFileAttributes(byte[] path) + JrtFileAttributes getFileAttributes(byte[] path, LinkOption... options) throws IOException { NodeAndImage ni = checkNode(path); + if (ni.node.isLink() && followLinks(options)) { + return new JrtFileAttributes(ni.node.resolveLink(true)); + } return new JrtFileAttributes(ni.node); } @@ -343,11 +392,13 @@ class JrtFileSystem extends FileSystem { return true; } - boolean isDirectory(byte[] path) + boolean isDirectory(byte[] path, boolean resolveLinks) throws IOException { ensureOpen(); NodeAndImage ni = checkNode(path); - return ni.node.isDirectory(); + return resolveLinks && ni.node.isLink()? + ni.node.resolveLink(true).isDirectory() : + ni.node.isDirectory(); } JrtPath toJrtPath(String path) { @@ -358,6 +409,28 @@ class JrtFileSystem extends FileSystem { return new JrtPath(this, path); } + boolean isSameFile(JrtPath p1, JrtPath p2) throws IOException { + NodeAndImage n1 = findNode(p1.getName()); + NodeAndImage n2 = findNode(p2.getName()); + return n1.node.equals(n2.node); + } + + boolean isLink(JrtPath jrtPath) throws IOException { + return findNode(jrtPath.getName()).node.isLink(); + } + + JrtPath resolveLink(JrtPath jrtPath) throws IOException { + NodeAndImage ni = findNode(jrtPath.getName()); + if (ni.node.isLink()) { + Node node = ni.node.resolveLink(); + return toJrtPath(node.getName().getBytesCopy()); + } + + return jrtPath; + } + + private Map> packagesTreeChildren = new ConcurrentHashMap<>(); + /** * returns the list of child paths of the given directory "path" * @@ -369,49 +442,73 @@ class JrtFileSystem extends FileSystem { Iterator iteratorOf(byte[] path, String childPrefix) throws IOException { NodeAndImage ni = checkNode(path); - if (!ni.node.isDirectory()) { + Node node = ni.node.resolveLink(true); + + if (!node.isDirectory()) { throw new NotDirectoryException(getString(path)); } - if (ni.node.isRootDir()) { + if (node.isRootDir()) { return rootDirIterator(path, childPrefix); + } else if (node.isModulesDir()) { + return modulesDirIterator(path, childPrefix); + } else if (node.isPackagesDir()) { + return packagesDirIterator(path, childPrefix); + } else if (node.getNameString().startsWith("/packages/")) { + if (ni.image != appImage) { + UTF8String name = node.getName(); + List children = packagesTreeChildren.get(name); + if (children != null) { + return nodesToIterator(toJrtPath(path), childPrefix, children); + } + + children = new ArrayList<>(); + children.addAll(node.getChildren()); + Node tmpNode = null; + // found in boot + if (ni.image == bootImage) { + tmpNode = extImage.findNode(name); + if (tmpNode != null) { + children.addAll(tmpNode.getChildren()); + } + } + + // found in ext + tmpNode = appImage.findNode(name); + if (tmpNode != null) { + children.addAll(tmpNode.getChildren()); + } + + packagesTreeChildren.put(name, children); + return nodesToIterator(toJrtPath(path), childPrefix, children); + } } - return nodesToIterator(toJrtPath(path), childPrefix, ni.node.getChildren()); + return nodesToIterator(toJrtPath(path), childPrefix, node.getChildren()); } private Iterator nodesToIterator(Path path, String childPrefix, List childNodes) { - List childPaths; - if (childPrefix == null) { - childPaths = childNodes.stream() - .filter(Node::isVisible) - .map(child -> toJrtPath(child.getNameString())) - .collect(Collectors.toCollection(ArrayList::new)); - } else { - childPaths = childNodes.stream() - .filter(Node::isVisible) - .map(child -> toJrtPath(childPrefix + child.getNameString().substring(1))) - .collect(Collectors.toCollection(ArrayList::new)); - } - return childPaths.iterator(); + Function f = childPrefix == null + ? child -> toJrtPath(child.getNameString()) + : child -> toJrtPath(childPrefix + child.getNameString().substring(1)); + return childNodes.stream().map(f).collect(toList()).iterator(); } - private List rootChildren; - private static void addRootDirContent(List dest, List src) { - for (Node n : src) { - // only module directories at the top level. Filter other stuff! - if (n.isModuleDir()) { - dest.add(n); + private void addRootDirContent(List children) { + for (Node child : children) { + if (!(child.isModulesDir() || child.isPackagesDir())) { + rootChildren.add(child); } } } + private List rootChildren; private synchronized void initRootChildren(byte[] path) { if (rootChildren == null) { rootChildren = new ArrayList<>(); - addRootDirContent(rootChildren, bootImage.findNode(path).getChildren()); - addRootDirContent(rootChildren, extImage.findNode(path).getChildren()); - addRootDirContent(rootChildren, appImage.findNode(path).getChildren()); + rootChildren.addAll(bootImage.findNode(path).getChildren()); + addRootDirContent(extImage.findNode(path).getChildren()); + addRootDirContent(appImage.findNode(path).getChildren()); } } @@ -420,6 +517,35 @@ class JrtFileSystem extends FileSystem { return nodesToIterator(rootPath, childPrefix, rootChildren); } + private List modulesChildren; + private synchronized void initModulesChildren(byte[] path) { + if (modulesChildren == null) { + modulesChildren = new ArrayList<>(); + modulesChildren.addAll(bootImage.findNode(path).getChildren()); + modulesChildren.addAll(appImage.findNode(path).getChildren()); + modulesChildren.addAll(extImage.findNode(path).getChildren()); + } + } + + private Iterator modulesDirIterator(byte[] path, String childPrefix) throws IOException { + initModulesChildren(path); + return nodesToIterator(new JrtPath(this, path), childPrefix, modulesChildren); + } + + private List packagesChildren; + private synchronized void initPackagesChildren(byte[] path) { + if (packagesChildren == null) { + packagesChildren = new ArrayList<>(); + packagesChildren.addAll(bootImage.findNode(path).getChildren()); + packagesChildren.addAll(extImage.findNode(path).getChildren()); + packagesChildren.addAll(appImage.findNode(path).getChildren()); + } + } + private Iterator packagesDirIterator(byte[] path, String childPrefix) throws IOException { + initPackagesChildren(path); + return nodesToIterator(new JrtPath(this, path), childPrefix, packagesChildren); + } + void createDirectory(byte[] dir, FileAttribute... attrs) throws IOException { throw readOnly(); diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java index a756d941e0a..54beafda0c9 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java @@ -145,6 +145,11 @@ public final class JrtFileSystemProvider extends FileSystemProvider { toJrtPath(path).checkAccess(modes); } + @Override + public Path readSymbolicLink(Path link) throws IOException { + return toJrtPath(link).readSymbolicLink(); + } + @Override public void copy(Path src, Path target, CopyOption... options) throws IOException @@ -169,7 +174,7 @@ public final class JrtFileSystemProvider extends FileSystemProvider { public V getFileAttributeView(Path path, Class type, LinkOption... options) { - return JrtFileAttributeView.get(toJrtPath(path), type); + return JrtFileAttributeView.get(toJrtPath(path), type, options); } @Override @@ -250,7 +255,7 @@ public final class JrtFileSystemProvider extends FileSystemProvider { throws IOException { if (type == BasicFileAttributes.class || type == JrtFileAttributes.class) - return (A)toJrtPath(path).getAttributes(); + return (A)toJrtPath(path).getAttributes(options); return null; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java index 3f25b9092ed..175ceaa1b04 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java @@ -55,6 +55,10 @@ final class JrtPath implements Path { this.path = normalize(path); } + byte[] getName() { + return path; + } + @Override public JrtPath getRoot() { if (this.isAbsolute()) @@ -140,10 +144,19 @@ final class JrtPath implements Path { @Override public JrtPath toRealPath(LinkOption... options) throws IOException { JrtPath realPath = new JrtPath(jrtfs, getResolvedPath()).toAbsolutePath(); + realPath = JrtFileSystem.followLinks(options)? jrtfs.resolveLink(this) : realPath; realPath.checkAccess(); return realPath; } + JrtPath readSymbolicLink() throws IOException { + if (! jrtfs.isLink(this)) { + throw new IOException("not a symbolic link"); + } + + return jrtfs.resolveLink(this); + } + boolean isHidden() { return false; } @@ -638,9 +651,9 @@ final class JrtPath implements Path { jrtfs.deleteFile(getResolvedPath(), false); } - JrtFileAttributes getAttributes() throws IOException + JrtFileAttributes getAttributes(LinkOption... options) throws IOException { - JrtFileAttributes zfas = jrtfs.getFileAttributes(getResolvedPath()); + JrtFileAttributes zfas = jrtfs.getFileAttributes(getResolvedPath(), options); if (zfas == null) throw new NoSuchFileException(toString()); return zfas; @@ -659,7 +672,7 @@ final class JrtPath implements Path { type = attribute.substring(0, colonPos++); attr = attribute.substring(colonPos); } - JrtFileAttributeView view = JrtFileAttributeView.get(this, type); + JrtFileAttributeView view = JrtFileAttributeView.get(this, type, options); if (view == null) throw new UnsupportedOperationException("view <" + view + "> is not supported"); view.setAttribute(attr, value); @@ -685,7 +698,7 @@ final class JrtPath implements Path { view = attributes.substring(0, colonPos++); attrs = attributes.substring(colonPos); } - JrtFileAttributeView jrtfv = JrtFileAttributeView.get(this, view); + JrtFileAttributeView jrtfv = JrtFileAttributeView.get(this, view, options); if (jrtfv == null) { throw new UnsupportedOperationException("view not supported"); } @@ -706,9 +719,10 @@ final class JrtPath implements Path { this.getFileSystem() != other.getFileSystem()) return false; this.checkAccess(); - ((JrtPath)other).checkAccess(); - return Arrays.equals(this.getResolvedPath(), - ((JrtPath)other).getResolvedPath()); + JrtPath path = (JrtPath)other; + path.checkAccess(); + return Arrays.equals(this.getResolvedPath(), path.getResolvedPath()) || + jrtfs.isSameFile(this, (JrtPath)other); } SeekableByteChannel newByteChannel(Set options, diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java index 8ff6291fbb8..c209ad2755e 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java @@ -42,6 +42,7 @@ final class SystemImages { static final Path bootImagePath; static final Path extImagePath; static final Path appImagePath; + static { PrivilegedAction pa = SystemImages::findHome; RUNTIME_HOME = AccessController.doPrivileged(pa); diff --git a/jdk/src/java.base/share/native/include/jvm.h b/jdk/src/java.base/share/native/include/jvm.h index 91decb2ed82..f1f40c04044 100644 --- a/jdk/src/java.base/share/native/include/jvm.h +++ b/jdk/src/java.base/share/native/include/jvm.h @@ -556,6 +556,48 @@ JVM_AssertionStatusDirectives(JNIEnv *env, jclass unused); JNIEXPORT jboolean JNICALL JVM_SupportsCX8(void); +/* + * jdk.internal.jimage + */ + +JNIEXPORT jlong JNICALL +JVM_ImageOpen(JNIEnv *env, const char *nativePath, jboolean big_endian); + +JNIEXPORT void JNICALL +JVM_ImageClose(JNIEnv *env, jlong id); + +JNIEXPORT jlong JNICALL +JVM_ImageGetIndexAddress(JNIEnv *env, jlong id); + +JNIEXPORT jlong JNICALL +JVM_ImageGetDataAddress(JNIEnv *env,jlong id); + +JNIEXPORT jboolean JNICALL +JVM_ImageRead(JNIEnv *env, jlong id, jlong offset, + unsigned char* uncompressedAddress, jlong uncompressed_size); + +JNIEXPORT jboolean JNICALL +JVM_ImageReadCompressed(JNIEnv *env, jlong id, jlong offset, + unsigned char* compressedBuffer, jlong compressed_size, + unsigned char* uncompressedBuffer, jlong uncompressed_size); + +JNIEXPORT const char* JNICALL +JVM_ImageGetStringBytes(JNIEnv *env, jlong id, jint offset); + +JNIEXPORT jlong* JNICALL +JVM_ImageGetAttributes(JNIEnv *env, jlong* rawAttributes, jlong id, jint offset); + +JNIEXPORT jsize JNICALL +JVM_ImageGetAttributesCount(JNIEnv *env); + +JNIEXPORT jlong* JNICALL +JVM_ImageFindAttributes(JNIEnv *env, jlong* rawAttributes, jbyte* rawBytes, jsize size, jlong id); + +JNIEXPORT jint* JNICALL +JVM_ImageAttributeOffsets(JNIEnv *env, jint* rawOffsets, unsigned int length, jlong id); + +JNIEXPORT unsigned int JNICALL +JVM_ImageAttributeOffsetsLength(JNIEnv *env, jlong id); /* * com.sun.dtrace.jsdt support */ diff --git a/jdk/src/java.base/share/native/libjava/Image.c b/jdk/src/java.base/share/native/libjava/Image.c new file mode 100644 index 00000000000..d82ca20560a --- /dev/null +++ b/jdk/src/java.base/share/native/libjava/Image.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include + +#include "jni.h" +#include "jvm.h" +#include "jdk_internal_jimage_ImageNativeSubstrate.h" + +JNIEXPORT jlong JNICALL +Java_jdk_internal_jimage_ImageNativeSubstrate_openImage(JNIEnv *env, + jclass cls, jstring path, jboolean big_endian) { + const char *nativePath; + jlong ret; + + nativePath = (*env)->GetStringUTFChars(env, path, NULL); + ret = JVM_ImageOpen(env, nativePath, big_endian); + (*env)->ReleaseStringUTFChars(env, path, nativePath); + return ret; +} + +JNIEXPORT void JNICALL +Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage(JNIEnv *env, + jclass cls, jlong id) { + JVM_ImageClose(env, id); +} + +JNIEXPORT jlong JNICALL +Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress(JNIEnv *env, + jclass cls, jlong id) { + return JVM_ImageGetIndexAddress(env, id); +} + +JNIEXPORT jlong JNICALL +Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress(JNIEnv *env, + jclass cls, jlong id) { + return JVM_ImageGetDataAddress(env, id); +} + +JNIEXPORT jboolean JNICALL +Java_jdk_internal_jimage_ImageNativeSubstrate_read(JNIEnv *env, + jclass cls, jlong id, jlong offset, + jobject uncompressedBuffer, jlong uncompressed_size) { + unsigned char* uncompressedAddress; + + uncompressedAddress = (unsigned char*) (*env)->GetDirectBufferAddress(env, uncompressedBuffer); + if (uncompressedBuffer == NULL) { + return JNI_FALSE; + } + return JVM_ImageRead(env, id, offset, uncompressedAddress, uncompressed_size); +} + +JNIEXPORT jboolean JNICALL +Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed(JNIEnv *env, + jclass cls, jlong id, jlong offset, + jobject compressedBuffer, jlong compressed_size, + jobject uncompressedBuffer, jlong uncompressed_size) { + // Get address of read direct buffer. + unsigned char* compressedAddress; + unsigned char* uncompressedAddress; + + compressedAddress = (unsigned char*) (*env)->GetDirectBufferAddress(env, compressedBuffer); + // Get address of decompression direct buffer. + uncompressedAddress = (unsigned char*) (*env)->GetDirectBufferAddress(env, uncompressedBuffer); + if (uncompressedBuffer == NULL || compressedBuffer == NULL) { + return JNI_FALSE; + } + return JVM_ImageReadCompressed(env, id, offset, compressedAddress, compressed_size, + uncompressedAddress, uncompressed_size); +} + +JNIEXPORT jbyteArray JNICALL +Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes(JNIEnv *env, + jclass cls, jlong id, jint offset) { + const char* data; + size_t size; + jbyteArray byteArray; + jbyte* rawBytes; + + data = JVM_ImageGetStringBytes(env, id, offset); + // Determine String length. + size = strlen(data); + // Allocate byte array. + byteArray = (*env)->NewByteArray(env, (jsize) size); + // Get array base address. + rawBytes = (*env)->GetByteArrayElements(env, byteArray, NULL); + // Copy bytes from image string table. + memcpy(rawBytes, data, size); + // Release byte array base address. + (*env)->ReleaseByteArrayElements(env, byteArray, rawBytes, 0); + return byteArray; +} + +JNIEXPORT jlongArray JNICALL +Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes(JNIEnv *env, + jclass cls, jlong id, jint offset) { + // Allocate a jlong large enough for all location attributes. + jlongArray attributes; + jlong* rawAttributes; + jlong* ret; + + attributes = (*env)->NewLongArray(env, JVM_ImageGetAttributesCount(env)); + // Get base address for jlong array. + rawAttributes = (*env)->GetLongArrayElements(env, attributes, NULL); + ret = JVM_ImageGetAttributes(env, rawAttributes, id, offset); + // Release jlong array base address. + (*env)->ReleaseLongArrayElements(env, attributes, rawAttributes, 0); + return ret == NULL ? NULL : attributes; +} + +JNIEXPORT jlongArray JNICALL +Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes(JNIEnv *env, + jclass cls, jlong id, jbyteArray utf8) { + // Allocate a jlong large enough for all location attributes. + jsize count; + jlongArray attributes; + jlong* rawAttributes; + jsize size; + jbyte* rawBytes; + jlong* ret; + + count = JVM_ImageGetAttributesCount(env); + attributes = (*env)->NewLongArray(env, JVM_ImageGetAttributesCount(env)); + // Get base address for jlong array. + rawAttributes = (*env)->GetLongArrayElements(env, attributes, NULL); + size = (*env)->GetArrayLength(env, utf8); + rawBytes = (*env)->GetByteArrayElements(env, utf8, NULL); + ret = JVM_ImageFindAttributes(env, rawAttributes, rawBytes, size, id); + (*env)->ReleaseByteArrayElements(env, utf8, rawBytes, 0); + // Release jlong array base address. + (*env)->ReleaseLongArrayElements(env, attributes, rawAttributes, 0); + return ret == NULL ? NULL : attributes; + +} + +JNIEXPORT jintArray JNICALL +Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets(JNIEnv *env, + jclass cls, jlong id) { + unsigned int length; + jintArray offsets; + jint* rawOffsets; + jint* ret; + + length = JVM_ImageAttributeOffsetsLength(env, id); + offsets = (*env)->NewIntArray(env, length); + // Get base address of result. + rawOffsets = (*env)->GetIntArrayElements(env, offsets, NULL); + ret = JVM_ImageAttributeOffsets(env, rawOffsets, length, id); + if (length == 0) { + return NULL; + } + // Release result base address. + (*env)->ReleaseIntArrayElements(env, offsets, rawOffsets, 0); + return ret == NULL ? NULL : offsets; +} diff --git a/jdk/src/java.base/unix/native/libjava/ConcurrentPReader_md.c b/jdk/src/java.base/unix/native/libjava/ConcurrentPReader_md.c deleted file mode 100644 index 1bb49d82229..00000000000 --- a/jdk/src/java.base/unix/native/libjava/ConcurrentPReader_md.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include -#include - -#include "jni.h" -#include "jni_util.h" -#include "jlong.h" -#include "jdk_internal_jimage_concurrent_ConcurrentPReader.h" - -#ifdef _ALLBSD_SOURCE - #define pread64 pread -#endif - -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ -} while(0) - -static jfieldID fd_fdID; - -JNIEXPORT void JNICALL -Java_jdk_internal_jimage_concurrent_ConcurrentPReader_initIDs(JNIEnv *env, jclass clazz) -{ - CHECK_NULL(clazz = (*env)->FindClass(env, "java/io/FileDescriptor")); - CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, clazz, "fd", "I")); -} - -JNIEXPORT jint JNICALL -Java_jdk_internal_jimage_concurrent_ConcurrentPReader_pread(JNIEnv *env, jclass clazz, - jobject fdo, jlong address, - jint len, jlong offset) -{ - jint fd = (*env)->GetIntField(env, fdo, fd_fdID); - void *buf = (void *)jlong_to_ptr(address); - int res; - RESTARTABLE(pread64(fd, buf, len, offset), res); - if (res == -1) { - JNU_ThrowIOExceptionWithLastError(env, "pread failed"); - } - return res; -} diff --git a/jdk/src/java.base/windows/native/libjava/ConcurrentPReader_md.c b/jdk/src/java.base/windows/native/libjava/ConcurrentPReader_md.c deleted file mode 100644 index c30120155ca..00000000000 --- a/jdk/src/java.base/windows/native/libjava/ConcurrentPReader_md.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include - -#include "jni_util.h" -#include "jlong.h" -#include "jdk_internal_jimage_concurrent_ConcurrentPReader.h" - -static jfieldID handle_fdID; - -JNIEXPORT void JNICALL -Java_jdk_internal_jimage_concurrent_ConcurrentPReader_initIDs(JNIEnv *env, jclass clazz) -{ - CHECK_NULL(clazz = (*env)->FindClass(env, "java/io/FileDescriptor")); - CHECK_NULL(handle_fdID = (*env)->GetFieldID(env, clazz, "handle", "J")); -} - -JNIEXPORT jint JNICALL -Java_jdk_internal_jimage_concurrent_ConcurrentPReader_pread(JNIEnv *env, jclass clazz, - jobject fdo, jlong address, - jint len, jlong offset) -{ - OVERLAPPED ov; - DWORD nread; - BOOL result; - - HANDLE handle = (HANDLE)(*env)->GetLongField(env, fdo, handle_fdID); - void *buf = (void *)jlong_to_ptr(address); - - ZeroMemory(&ov, sizeof(ov)); - ov.Offset = (DWORD)offset; - ov.OffsetHigh = (DWORD)(offset >> 32); - - result = ReadFile(handle, (LPVOID)buf, len, &nread, &ov); - if (result == 0) { - JNU_ThrowIOExceptionWithLastError(env, "ReadFile failed"); - } - - return nread; -} - diff --git a/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/ExtractedImage.java b/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/ExtractedImage.java new file mode 100644 index 00000000000..cda1a682edd --- /dev/null +++ b/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/ExtractedImage.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.tools.jimage; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Stream; +import jdk.internal.jimage.Archive; +import jdk.internal.jimage.ImageFileCreator; +import jdk.internal.jimage.ImageModuleData; +import jdk.internal.jimage.ImageModuleDataWriter; + +/** + * + * Support for extracted image. + */ +public final class ExtractedImage { + + /** + * An Archive backed by a directory. + */ + public class DirArchive implements Archive { + + /** + * A File located in a Directory. + */ + private class FileEntry extends Archive.Entry { + + private final long size; + private final Path path; + + FileEntry(Path path, String name) { + super(DirArchive.this, getPathName(path), name, + Archive.Entry.EntryType.CLASS_OR_RESOURCE); + this.path = path; + try { + size = Files.size(path); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Returns the number of bytes of this file. + */ + @Override + public long size() { + return size; + } + + @Override + public InputStream stream() throws IOException { + InputStream stream = Files.newInputStream(path); + open.add(stream); + return stream; + } + } + + private final Path dirPath; + private final String moduleName; + private final List open = new ArrayList<>(); + private final int chop; + + protected DirArchive(Path dirPath) throws IOException { + if (!Files.isDirectory(dirPath)) { + throw new IOException("Not a directory"); + } + chop = dirPath.toString().length() + 1; + this.moduleName = dirPath.getFileName().toString(); + System.out.println("Module name " + this.moduleName); + this.dirPath = dirPath; + } + + @Override + public String moduleName() { + return moduleName; + } + + @Override + public Stream entries() { + try { + return Files.walk(dirPath).map(this::toEntry).filter(n -> n != null); + } catch(IOException ex) { + throw new RuntimeException(ex); + } + } + + private Archive.Entry toEntry(Path p) { + if (Files.isDirectory(p)) { + return null; + } + String name = getPathName(p).substring(chop); + if (name.startsWith("_")) { + return null; + } + if (verbose) { + String verboseName = moduleName + "/" + name; + log.println(verboseName); + } + + return new FileEntry(p, name); + } + + @Override + public void close() throws IOException { + IOException e = null; + for (InputStream stream : open) { + try { + stream.close(); + } catch (IOException ex) { + if (e == null) { + e = ex; + } else { + e.addSuppressed(ex); + } + } + } + if (e != null) { + throw e; + } + } + + @Override + public void open() throws IOException { + // NOOP + } + } + private Map> modulePackages = new LinkedHashMap<>(); + private Set archives = new HashSet<>(); + private final PrintWriter log; + private final boolean verbose; + + ExtractedImage(Path dirPath, PrintWriter log, + boolean verbose) throws IOException { + if (!Files.isDirectory(dirPath)) { + throw new IOException("Not a directory"); + } + Files.walk(dirPath, 1).forEach((p) -> { + try { + if (!dirPath.equals(p)) { + String name = getPathName(p); + if (name.endsWith(ImageModuleData.META_DATA_EXTENSION)) { + List lines = Files.readAllLines(p); + for (Entry> entry + : ImageModuleDataWriter.toModulePackages(lines).entrySet()) { + Set pkgs = new HashSet<>(); + pkgs.addAll(entry.getValue()); + modulePackages.put(entry.getKey(), pkgs); + } + modulePackages = Collections.unmodifiableMap(modulePackages); + } else { + if (Files.isDirectory(p)) { + Archive a = new DirArchive(p); + archives.add(a); + } + } + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } + }); + archives = Collections.unmodifiableSet(archives); + this.log = log; + this.verbose = verbose; + } + + void recreateJImage(Path path) throws IOException { + + ImageFileCreator.recreateJimage(path, archives, modulePackages); + } + + private static String getPathName(Path path) { + return path.toString().replace(File.separatorChar, '/'); + } +} diff --git a/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/JImageTask.java b/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/JImageTask.java index 6e7e29ebc69..077100f9be0 100644 --- a/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/JImageTask.java +++ b/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/JImageTask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * 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,141 +25,98 @@ package jdk.tools.jimage; -import java.io.BufferedOutputStream; -import java.io.DataOutputStream; import java.io.File; import java.io.IOException; -import java.io.OutputStream; import java.io.PrintWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.ArrayList; +import static java.nio.file.StandardOpenOption.READ; +import static java.nio.file.StandardOpenOption.WRITE; import java.util.LinkedList; import java.util.List; -import java.util.Locale; -import java.util.MissingResourceException; -import java.util.ResourceBundle; -import java.util.stream.Collectors; -import java.util.stream.Stream; import jdk.internal.jimage.BasicImageReader; -import jdk.internal.jimage.BasicImageWriter; import jdk.internal.jimage.ImageHeader; +import static jdk.internal.jimage.ImageHeader.MAGIC; +import static jdk.internal.jimage.ImageHeader.MAJOR_VERSION; +import static jdk.internal.jimage.ImageHeader.MINOR_VERSION; import jdk.internal.jimage.ImageLocation; -import jdk.internal.jimage.PackageModuleMap; +import jdk.internal.jimage.ImageModuleData; +import jdk.internal.jimage.ImageResourcesTree; +import jdk.tools.jimage.TaskHelper.BadArgs; +import jdk.tools.jimage.TaskHelper.HiddenOption; +import jdk.tools.jimage.TaskHelper.Option; +import jdk.tools.jimage.TaskHelper.OptionsHelper; class JImageTask { - static class BadArgs extends Exception { - static final long serialVersionUID = 8765093759964640723L; // ## re-generate - final String key; - final Object[] args; - boolean showUsage; - BadArgs(String key, Object... args) { - super(JImageTask.getMessage(key, args)); - this.key = key; - this.args = args; - } - - BadArgs showUsage(boolean b) { - showUsage = b; - return this; - } - } - - static abstract class Option { - final boolean hasArg; - final String[] aliases; - - Option(boolean hasArg, String... aliases) { - this.hasArg = hasArg; - this.aliases = aliases; - } - - boolean isHidden() { - return false; - } - - boolean matches(String opt) { - for (String a : aliases) { - if (a.equals(opt)) { - return true; - } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { - return true; - } - } - return false; - } - - boolean ignoreRest() { - return false; - } - - abstract void process(JImageTask task, String opt, String arg) throws BadArgs; - } - - static abstract class HiddenOption extends Option { - HiddenOption(boolean hasArg, String... aliases) { - super(hasArg, aliases); - } - - @Override - boolean isHidden() { - return true; - } - } - - static Option[] recognizedOptions = { - new Option(true, "--dir") { + static final Option[] recognizedOptions = { + new Option(true, "--dir") { @Override - void process(JImageTask task, String opt, String arg) throws BadArgs { + protected void process(JImageTask task, String opt, String arg) throws BadArgs { task.options.directory = arg; } }, - new HiddenOption(false, "--fullversion") { + new HiddenOption(false, "--fullversion") { @Override - void process(JImageTask task, String opt, String arg) { + protected void process(JImageTask task, String opt, String arg) { task.options.fullVersion = true; } }, - new Option(false, "--help") { + new Option(false, "--help") { @Override - void process(JImageTask task, String opt, String arg) { + protected void process(JImageTask task, String opt, String arg) { task.options.help = true; } }, - new Option(false, "--verbose") { + + new Option(true, "--flags") { @Override - void process(JImageTask task, String opt, String arg) throws BadArgs { + protected void process(JImageTask task, String opt, String arg) { + task.options.flags = arg; + } + }, + + new Option(false, "--verbose") { + @Override + protected void process(JImageTask task, String opt, String arg) throws BadArgs { task.options.verbose = true; } }, - new Option(false, "--version") { + new Option(false, "--version") { @Override - void process(JImageTask task, String opt, String arg) { + protected void process(JImageTask task, String opt, String arg) { task.options.version = true; } }, }; + private static final TaskHelper taskHelper + = new TaskHelper("jdk.tools.jimage.resources.jimage"); + private static final OptionsHelper optionsHelper + = taskHelper.newOptionsHelper(JImageTask.class, recognizedOptions); - static class Options { + static class OptionsValues { Task task = Task.LIST; String directory = "."; boolean fullVersion; boolean help; + String flags; boolean verbose; boolean version; List jimages = new LinkedList<>(); } private static final String PROGNAME = "jimage"; - private final Options options = new Options(); + private final OptionsValues options = new OptionsValues(); enum Task { - RECREATE, EXTRACT, INFO, LIST, + RECREATE, + SET, VERIFY }; @@ -210,23 +167,29 @@ class JImageTask { int run(String[] args) { if (log == null) { - log = new PrintWriter(System.out); + setLog(new PrintWriter(System.out)); } try { - handleOptions(args); + List unhandled = optionsHelper.handleOptions(this, args); + if(!unhandled.isEmpty()) { + options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase()); + for(int i = 1; i < unhandled.size(); i++) { + options.jimages.add(new File(unhandled.get(i))); + } + } if (options.help) { - showHelp(); + optionsHelper.showHelp(PROGNAME, "recreate only options:"); } if (options.version || options.fullVersion) { - showVersion(options.fullVersion); + taskHelper.showVersion(options.fullVersion); } boolean ok = run(); return ok ? EXIT_OK : EXIT_ERROR; } catch (BadArgs e) { - reportError(e.key, e.args); + taskHelper.reportError(e.key, e.args); if (e.showUsage) { - log.println(getMessage("main.usage.summary", PROGNAME)); + log.println(taskHelper.getMessage("main.usage.summary", PROGNAME)); } return EXIT_CMDERR; } catch (Exception x) { @@ -237,98 +200,26 @@ class JImageTask { } } - static final String MODULES_ENTRY = PackageModuleMap.MODULES_ENTRY; - static final String PACKAGES_ENTRY = "/" + PackageModuleMap.PACKAGES_ENTRY; - private void recreate() throws IOException, BadArgs { File directory = new File(options.directory); - Path dirPath = directory.toPath(); - int chop = dirPath.toString().length() + 1; - if (!directory.isDirectory()) { - throw new BadArgs("err.not.a.dir", directory.getAbsolutePath()); + throw taskHelper.newBadArgs("err.not.a.dir", directory.getAbsolutePath()); } - + Path dirPath = directory.toPath(); if (options.jimages.isEmpty()) { - throw new BadArgs("err.jimage.not.specified"); + throw taskHelper.newBadArgs("err.jimage.not.specified"); } else if (options.jimages.size() != 1) { - throw new BadArgs("err.only.one.jimage"); + throw taskHelper.newBadArgs("err.only.one.jimage"); } - File jimage = options.jimages.get(0); - final List files = new ArrayList<>(); - final BasicImageWriter writer = new BasicImageWriter(); - final Long longZero = 0L; + Path jimage = options.jimages.get(0).toPath(); - // Note: code sensitive to Netbeans parser crashing. - long total = Files.walk(dirPath).reduce(longZero, (Long offset, Path path) -> { - long size = 0; - String pathString = path.toString(); - - if (pathString.length() < chop || pathString.startsWith(".")) { - return 0L; - } - - File file = path.toFile(); - - if (file.isFile()) { - String name = pathString.substring(chop).replace(File.separatorChar, '/'); - - if (options.verbose) { - log.println(name); - } - - if (name.endsWith(MODULES_ENTRY) || name.endsWith(PACKAGES_ENTRY)) { - try { - try (Stream lines = Files.lines(path)) { - size = lines.peek(s -> writer.addString(s)).count() * 4; - } - } catch (IOException ex) { - // Caught again when writing file. - size = 0; - } - } else { - size = file.length(); - } - - writer.addLocation(name, offset, 0L, size); - files.add(file); - } - - return offset + size; - }, - (Long offsetL, Long offsetR) -> { return longZero; } ); - - if (jimage.createNewFile()) { - try (OutputStream os = Files.newOutputStream(jimage.toPath()); - BufferedOutputStream bos = new BufferedOutputStream(os); - DataOutputStream out = new DataOutputStream(bos)) { - - byte[] index = writer.getBytes(); - out.write(index, 0, index.length); - - for (File file : files) { - try { - Path path = file.toPath(); - String name = path.toString().replace(File.separatorChar, '/'); - - if (name.endsWith(MODULES_ENTRY) || name.endsWith(PACKAGES_ENTRY)) { - for (String line: Files.readAllLines(path)) { - int off = writer.addString(line); - out.writeInt(off); - } - } else { - Files.copy(path, out); - } - } catch (IOException ex) { - throw new BadArgs("err.cannot.read.file", file.getName()); - } - } - } + if (jimage.toFile().createNewFile()) { + ExtractedImage img = new ExtractedImage(dirPath, log, options.verbose); + img.recreateJImage(jimage); } else { - throw new BadArgs("err.jimage.already.exists", jimage.getName()); + throw taskHelper.newBadArgs("err.jimage.already.exists", jimage.getFileName()); } - } private void title(File file, BasicImageReader reader) { @@ -351,10 +242,12 @@ class JImageTask { } private interface ResourceAction { - public void apply(BasicImageReader reader, String name, ImageLocation location) throws IOException, BadArgs; + public void apply(BasicImageReader reader, String name, + ImageLocation location) throws IOException, BadArgs; } - private void extract(BasicImageReader reader, String name, ImageLocation location) throws IOException, BadArgs { + private void extract(BasicImageReader reader, String name, + ImageLocation location) throws IOException, BadArgs { File directory = new File(options.directory); byte[] bytes = reader.getResource(location); File resource = new File(directory, name); @@ -362,21 +255,23 @@ class JImageTask { if (parent.exists()) { if (!parent.isDirectory()) { - throw new BadArgs("err.cannot.create.dir", parent.getAbsolutePath()); + throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath()); } } else if (!parent.mkdirs()) { - throw new BadArgs("err.cannot.create.dir", parent.getAbsolutePath()); + throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath()); } - if (name.endsWith(MODULES_ENTRY) || name.endsWith(PACKAGES_ENTRY)) { - List names = reader.getNames(bytes); - Files.write(resource.toPath(), names); + if (name.endsWith(ImageModuleData.META_DATA_EXTENSION)) { + ImageModuleData imageModuleData = new ImageModuleData(reader, bytes); + List lines = imageModuleData.fromModulePackages(); + Files.write(resource.toPath(), lines); } else { - Files.write(resource.toPath(), bytes); + if (!ImageResourcesTree.isTreeInfoResource(name)) { + Files.write(resource.toPath(), bytes); + } } } - private static final int NAME_WIDTH = 40; private static final int NUMBER_WIDTH = 12; private static final int OFFSET_WIDTH = NUMBER_WIDTH; private static final int SIZE_WIDTH = NUMBER_WIDTH; @@ -397,12 +292,14 @@ class JImageTask { } } - private void info(File file, BasicImageReader reader) { + private void info(File file, BasicImageReader reader) throws IOException { ImageHeader header = reader.getHeader(); log.println(" Major Version: " + header.getMajorVersion()); log.println(" Minor Version: " + header.getMinorVersion()); - log.println(" Location Count: " + header.getLocationCount()); + log.println(" Flags: " + Integer.toHexString(header.getMinorVersion())); + log.println(" Resource Count: " + header.getResourceCount()); + log.println(" Table Length: " + header.getTableLength()); log.println(" Offsets Size: " + header.getOffsetsSize()); log.println(" Redirects Size: " + header.getRedirectSize()); log.println(" Locations Size: " + header.getLocationsSize()); @@ -414,16 +311,39 @@ class JImageTask { print(reader, name); } - void verify(BasicImageReader reader, String name, ImageLocation location) { - if (name.endsWith(".class")) { - byte[] bytes; + void set(File file, BasicImageReader reader) throws BadArgs { + try { + ImageHeader oldHeader = reader.getHeader(); + + int value = 0; try { - bytes = reader.getResource(location); - } catch (IOException ex) { - log.println(ex); - bytes = null; + value = Integer.valueOf(options.flags); + } catch (NumberFormatException ex) { + throw taskHelper.newBadArgs("err.flags.not.int", options.flags); } + ImageHeader newHeader = new ImageHeader(MAGIC, MAJOR_VERSION, MINOR_VERSION, + value, + oldHeader.getResourceCount(), oldHeader.getTableLength(), + oldHeader.getLocationsSize(), oldHeader.getStringsSize()); + + ByteBuffer buffer = ByteBuffer.allocate(ImageHeader.getHeaderSize()); + buffer.order(ByteOrder.nativeOrder()); + newHeader.writeTo(buffer); + buffer.rewind(); + + try (FileChannel channel = FileChannel.open(file.toPath(), READ, WRITE)) { + channel.write(buffer, 0); + } + } catch (IOException ex) { + throw taskHelper.newBadArgs("err.cannot.update.file", file.getName()); + } + } + + void verify(BasicImageReader reader, String name, ImageLocation location) { + if (name.endsWith(".class")) { + byte[] bytes = reader.getResource(location); + if (bytes == null || bytes.length <= 4 || (bytes[0] & 0xFF) != 0xCA || (bytes[1] & 0xFF) != 0xFE || @@ -435,10 +355,11 @@ class JImageTask { } } - private void iterate(JImageAction jimageAction, ResourceAction resourceAction) throws IOException, BadArgs { + private void iterate(JImageAction jimageAction, + ResourceAction resourceAction) throws IOException, BadArgs { for (File file : options.jimages) { if (!file.exists() || !file.isFile()) { - throw new BadArgs("err.not.a.jimage", file.getName()); + throw taskHelper.newBadArgs("err.not.a.jimage", file.getName()); } String path = file.getCanonicalPath(); @@ -449,11 +370,13 @@ class JImageTask { } if (resourceAction != null) { - String[] entryNames = reader.getEntryNames(true); + String[] entryNames = reader.getEntryNames(); for (String name : entryNames) { - ImageLocation location = reader.findLocation(name); - resourceAction.apply(reader, name, location); + if (!ImageResourcesTree.isTreeInfoResource(name)) { + ImageLocation location = reader.findLocation(name); + resourceAction.apply(reader, name, location); + } } } } @@ -461,9 +384,6 @@ class JImageTask { private boolean run() throws IOException, BadArgs { switch (options.task) { - case RECREATE: - recreate(); - break; case EXTRACT: iterate(null, this::extract); break; @@ -473,11 +393,17 @@ class JImageTask { case LIST: iterate(this::listTitle, this::list); break; + case RECREATE: + recreate(); + break; + case SET: + iterate(this::set, null); + break; case VERIFY: iterate(this::title, this::verify); break; default: - throw new BadArgs("err.invalid.task", options.task.name()).showUsage(true); + throw taskHelper.newBadArgs("err.invalid.task", options.task.name()).showUsage(true); } return true; } @@ -485,112 +411,6 @@ class JImageTask { private PrintWriter log; void setLog(PrintWriter out) { log = out; - } - public void handleOptions(String[] args) throws BadArgs { - // process options - int first = 0; - - if (args.length == 0) { - return; - } - - String arg = args[first]; - - if (!arg.startsWith("-")) { - try { - options.task = Enum.valueOf(Task.class, arg.toUpperCase()); - first++; - } catch (IllegalArgumentException e) { - throw new BadArgs("err.invalid.task", arg).showUsage(true); - } - } - - for (int i = first; i < args.length; i++) { - arg = args[i]; - - if (arg.charAt(0) == '-') { - Option option = getOption(arg); - String param = null; - - if (option.hasArg) { - if (arg.startsWith("--") && arg.indexOf('=') > 0) { - param = arg.substring(arg.indexOf('=') + 1, arg.length()); - } else if (i + 1 < args.length) { - param = args[++i]; - } - - if (param == null || param.isEmpty() || param.charAt(0) == '-') { - throw new BadArgs("err.missing.arg", arg).showUsage(true); - } - } - - option.process(this, arg, param); - - if (option.ignoreRest()) { - i = args.length; - } - } else { - File file = new File(arg); - options.jimages.add(file); - } - } - } - - private Option getOption(String name) throws BadArgs { - for (Option o : recognizedOptions) { - if (o.matches(name)) { - return o; - } - } - throw new BadArgs("err.unknown.option", name).showUsage(true); - } - - private void reportError(String key, Object... args) { - log.println(getMessage("error.prefix") + " " + getMessage(key, args)); - } - - private void warning(String key, Object... args) { - log.println(getMessage("warn.prefix") + " " + getMessage(key, args)); - } - - private void showHelp() { - log.println(getMessage("main.usage", PROGNAME)); - for (Option o : recognizedOptions) { - String name = o.aliases[0].substring(1); // there must always be at least one name - name = name.charAt(0) == '-' ? name.substring(1) : name; - if (o.isHidden() || name.equals("h")) { - continue; - } - log.println(getMessage("main.opt." + name)); - } - } - - private void showVersion(boolean full) { - log.println(version(full ? "full" : "release")); - } - - private String version(String key) { - return System.getProperty("java.version"); - } - - static String getMessage(String key, Object... args) { - try { - return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args); - } catch (MissingResourceException e) { - throw new InternalError("Missing message: " + key); - } - } - - private static class ResourceBundleHelper { - static final ResourceBundle bundle; - - static { - Locale locale = Locale.getDefault(); - try { - bundle = ResourceBundle.getBundle("jdk.tools.jimage.resources.jimage", locale); - } catch (MissingResourceException e) { - throw new InternalError("Cannot find jimage resource bundle for locale " + locale); - } - } + taskHelper.setLog(log); } } diff --git a/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/TaskHelper.java b/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/TaskHelper.java new file mode 100644 index 00000000000..db4f4e16978 --- /dev/null +++ b/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/TaskHelper.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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.tools.jimage; + +import java.io.PrintWriter; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * + * JImage tools shared helper. + */ +public final class TaskHelper { + + public class BadArgs extends Exception { + + static final long serialVersionUID = 8765093759964640721L; + + private BadArgs(String key, Object... args) { + super(bundleHelper.getMessage(key, args)); + this.key = key; + this.args = args; + } + + public BadArgs showUsage(boolean b) { + showUsage = b; + return this; + } + public final String key; + public final Object[] args; + public boolean showUsage; + } + + public static abstract class Option { + + final boolean hasArg; + final String[] aliases; + + public Option(boolean hasArg, String... aliases) { + this.hasArg = hasArg; + this.aliases = aliases; + } + + public boolean isHidden() { + return false; + } + + public boolean matches(String opt) { + for (String a : aliases) { + if (a.equals(opt)) { + return true; + } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { + return true; + } + } + return false; + } + + public boolean ignoreRest() { + return false; + } + + protected abstract void process(T task, String opt, String arg) throws BadArgs; + } + + public static abstract class HiddenOption extends Option { + + public HiddenOption(boolean hasArg, String... aliases) { + super(hasArg, aliases); + } + + @Override + public boolean isHidden() { + return true; + } + } + + private class ResourceBundleHelper { + + private final ResourceBundle bundle; + + ResourceBundleHelper(String path) { + Locale locale = Locale.getDefault(); + try { + bundle = ResourceBundle.getBundle(path, locale); + } catch (MissingResourceException e) { + throw new InternalError("Cannot find resource bundle for locale " + locale); + } + } + + String getMessage(String key, Object... args) { + String val = bundle.getString(key); + return MessageFormat.format(val, args); + } + + } + + public class OptionsHelper { + + private final List> options; + + OptionsHelper(List> options) { + this.options = options; + } + + public List handleOptions(T task, String[] args) throws BadArgs { + List rest = new ArrayList<>(); + // process options + for (int i = 0; i < args.length; i++) { + if (args[i].charAt(0) == '-') { + String name = args[i]; + Option option = getOption(name); + if (option == null) { + throw new BadArgs("err.unknown.option", name).showUsage(true); + } + String param = null; + if (option.hasArg) { + if (name.startsWith("--") && name.indexOf('=') > 0) { + param = name.substring(name.indexOf('=') + 1, name.length()); + } else if (i + 1 < args.length) { + param = args[++i]; + } + if (param == null || param.isEmpty() || param.charAt(0) == '-') { + throw new BadArgs("err.missing.arg", name).showUsage(true); + } + } + option.process(task, name, param); + if (option.ignoreRest()) { + i = args.length; + } + } else { + rest.add(args[i]); + } + } + return rest; + } + + private Option getOption(String name) throws BadArgs { + for (Option o : options) { + if (o.matches(name)) { + return o; + } + } + return null; + } + + public void showHelp(String progName, String pluginsHeader) { + log.println(bundleHelper.getMessage("main.usage", progName)); + for (Option o : options) { + String name = o.aliases[0].substring(1); // there must always be at least one name + name = name.charAt(0) == '-' ? name.substring(1) : name; + if (o.isHidden() || name.equals("h")) { + continue; + } + log.println(bundleHelper.getMessage("main.opt." + name)); + } + } + } + + private PrintWriter log; + private final ResourceBundleHelper bundleHelper; + + public TaskHelper(String path) { + this.bundleHelper = new ResourceBundleHelper(path); + } + + public OptionsHelper newOptionsHelper(Class clazz, Option[] options) { + List> optionsList = new ArrayList<>(); + for (Option o : options) { + @SuppressWarnings("unchecked") + Option opt = (Option) o; + optionsList.add(opt); + } + return new OptionsHelper<>(optionsList); + } + + public BadArgs newBadArgs(String key, Object... args) { + return new BadArgs(key, args); + } + + public String getMessage(String key, Object... args) { + return bundleHelper.getMessage(key, args); + } + + public void setLog(PrintWriter log) { + this.log = log; + } + + public void reportError(String key, Object... args) { + log.println(bundleHelper.getMessage("error.prefix") + " " + bundleHelper.getMessage(key, args)); + } + + public void warning(String key, Object... args) { + log.println(bundleHelper.getMessage("warn.prefix") + " " + bundleHelper.getMessage(key, args)); + } + + public void showVersion(boolean full) { + log.println(version(full ? "full" : "release")); + } + + public String version(String key) { + return System.getProperty("java.version"); + } + +} diff --git a/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/resources/jimage.properties b/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/resources/jimage.properties index f47e1aaf9eb..27ba361b091 100644 --- a/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/resources/jimage.properties +++ b/jdk/src/jdk.dev/share/classes/jdk/tools/jimage/resources/jimage.properties @@ -1,16 +1,17 @@ main.usage.summary=\ -Usage: {0} jimage...\n\ +Usage: {0} jimage...\n\ use --help for a list of possible options main.usage=\ -Usage: {0} jimage...\n\ +Usage: {0} jimage...\n\ \n\ \ extract - Extract all jimage entries into separate files into the directory\n\ \ specified by --dir= (default='.')\n\ -\ recreate - Reconstructs a jimage from an extracted directory (--dir)\n\ \ info - Prints information specified in the jimage header.\n\ \ list - Prints the names of all the entries in the jimage. When used with\n\ \ --verbose will also print entry attributes ex. size and offset.\n\ +\ recreate - Reconstructs a jimage from an extracted directory (--dir)\n\ +\ set - sets the value of specific jimage header entries\n\ \ verify - Reports errors on any .class entries that don't verify as classes.\n\ \n\ Possible options include: @@ -19,27 +20,32 @@ error.prefix=Error: warn.prefix=Warning: main.opt.dir=\ -\ --dir Target directory for create/expand +\ --dir Target directory for extract/recreate -main.opt.verbose=\ -\ --verbose Verbose listing +main.opt.flags=\ +\ --flags=value Set the jimage flags to value main.opt.help=\ \ --help Print this usage message +main.opt.verbose=\ +\ --verbose Verbose listing + main.opt.version=\ \ --version Version information -err.invalid.task=task must be list|expand|info|verify: {0} -err.not.a.dir=not a directory: {0} -err.jimage.not.specified=no jimage specified -err.only.one.jimage=only one jimage should be specified -err.jimage.already.exists=jimage already exists: {0} -err.cannot.read.file=cannot read file: {0} err.cannot.create.dir=cannot create directory: {0} -err.not.a.jimage=not a jimage file: {0} -err.unknown.option=unknown option: {0} -err.missing.arg=no value given for {0} +err.cannot.read.file=cannot read file: {0} +err.cannot.update.file=cannot update file: {0} +err.flags.not.int=--flags value not integer: {0} err.internal.error=internal error: {0} {1} {2} err.invalid.arg.for.option=invalid argument for option: {0} +err.invalid.task=task must be extract|recreate|info|list|verify: {0} +err.jimage.already.exists=jimage already exists: {0} +err.jimage.not.specified=no jimage specified +err.missing.arg=no value given for {0} +err.not.a.dir=not a directory: {0} +err.not.a.jimage=not a jimage file: {0} +err.only.one.jimage=only one jimage should be specified err.option.unsupported={0} not supported: {1} +err.unknown.option=unknown option: {0} diff --git a/jdk/src/jdk.rmic/share/classes/sun/tools/java/ClassPath.java b/jdk/src/jdk.rmic/share/classes/sun/tools/java/ClassPath.java index 4d366fb8dd0..656eca1a6f4 100644 --- a/jdk/src/jdk.rmic/share/classes/sun/tools/java/ClassPath.java +++ b/jdk/src/jdk.rmic/share/classes/sun/tools/java/ClassPath.java @@ -394,7 +394,7 @@ final class JrtClassPathEntry extends ClassPathEntry { this.pkgDirs = new HashMap<>(); // fill in module directories at the root dir - Path root = fs.getPath("/"); + Path root = fs.getPath("/modules"); try { try (DirectoryStream stream = Files.newDirectoryStream(root)) { for (Path entry: stream) { diff --git a/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java b/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java index 8df27ef7f04..58d5097beca 100644 --- a/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java +++ b/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java @@ -221,8 +221,8 @@ public class FieldSetAccessibleTest { Stream build() { return roots.stream().flatMap(this::toStream) - .filter(x -> x.getNameCount() > 1) - .map( x-> x.subpath(1, x.getNameCount())) + .filter(x -> x.getNameCount() > 2) + .map( x-> x.subpath(2, x.getNameCount())) .map( x -> x.toString()) .filter(s -> s.endsWith(".class")); } diff --git a/jdk/test/java/nio/Buffer/LimitDirectMemory.sh b/jdk/test/java/nio/Buffer/LimitDirectMemory.sh index 027d6279b49..f2e7a93b878 100644 --- a/jdk/test/java/nio/Buffer/LimitDirectMemory.sh +++ b/jdk/test/java/nio/Buffer/LimitDirectMemory.sh @@ -28,6 +28,7 @@ # @summary Test option to limit direct memory allocation # # @build LimitDirectMemory +# @ignore JDK-8129343 # @run shell LimitDirectMemory.sh TMP1=tmp_$$ diff --git a/jdk/test/java/nio/charset/Charset/NIOCharsetAvailabilityTest.java b/jdk/test/java/nio/charset/Charset/NIOCharsetAvailabilityTest.java index f2a1e05e608..601ca24faa9 100644 --- a/jdk/test/java/nio/charset/Charset/NIOCharsetAvailabilityTest.java +++ b/jdk/test/java/nio/charset/Charset/NIOCharsetAvailabilityTest.java @@ -46,9 +46,9 @@ public class NIOCharsetAvailabilityTest { // two known charset implementation packages FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); Set charsets = - Stream.concat(Files.walk(fs.getPath("/java.base/sun/nio/cs/")), - Files.walk(fs.getPath("/jdk.charsets/sun/nio/cs/ext/"))) - .map( p -> p.subpath(1, p.getNameCount()).toString()) + Stream.concat(Files.walk(fs.getPath("/modules/java.base/sun/nio/cs/")), + Files.walk(fs.getPath("/modules/jdk.charsets/sun/nio/cs/ext/"))) + .map( p -> p.subpath(2, p.getNameCount()).toString()) .filter( s -> s.indexOf("$") == -1 && s.endsWith(".class")) .map( s -> { try { diff --git a/jdk/test/java/nio/file/spi/SetDefaultProvider.java b/jdk/test/java/nio/file/spi/SetDefaultProvider.java index 10629f89b1d..bcb0ae24b1b 100644 --- a/jdk/test/java/nio/file/spi/SetDefaultProvider.java +++ b/jdk/test/java/nio/file/spi/SetDefaultProvider.java @@ -25,6 +25,7 @@ * @bug 4313887 7006126 * @summary Unit test for java.nio.file.spi.FileSystemProvider * @build TestProvider SetDefaultProvider + * @ignore JDK-8129343 * @run main/othervm -Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider SetDefaultProvider */ diff --git a/jdk/test/jdk/internal/jimage/VerifyJimage.java b/jdk/test/jdk/internal/jimage/VerifyJimage.java index fbb9fd665c8..406b1fb92b1 100644 --- a/jdk/test/jdk/internal/jimage/VerifyJimage.java +++ b/jdk/test/jdk/internal/jimage/VerifyJimage.java @@ -217,7 +217,12 @@ public class VerifyJimage { } int entries() { - return getHeader().getLocationCount(); + try { + return getHeader().getTableLength(); + } catch (IOException ex) { + failed.add(imageName() + ": can't access header"); + return 0; + } } void compare(String entry, Path p) { diff --git a/jdk/test/jdk/internal/jrtfs/Basic.java b/jdk/test/jdk/internal/jrtfs/Basic.java index 3b5fedaecbc..5b99a5cf83f 100644 --- a/jdk/test/jdk/internal/jrtfs/Basic.java +++ b/jdk/test/jdk/internal/jrtfs/Basic.java @@ -98,8 +98,8 @@ public class Basic { @DataProvider(name = "knownClassFiles") private Object[][] knownClassFiles() { return new Object[][] { - { "/java.base/java/lang/Object.class" }, - { "java.base/java/lang/Object.class" }, + { "/modules/java.base/java/lang/Object.class" }, + { "modules/java.base/java/lang/Object.class" }, }; } @@ -126,14 +126,14 @@ public class Basic { { "./" }, { "/." }, { "/./" }, - { "/java.base/.." }, - { "/java.base/../" }, - { "/java.base/../." }, - { "/java.base" }, - { "/java.base/java/lang" }, - { "java.base/java/lang" }, - { "/java.base/java/lang/" }, - { "java.base/java/lang/" } + { "/modules/java.base/.." }, + { "/modules/java.base/../" }, + { "/modules/java.base/../." }, + { "/modules/java.base" }, + { "/modules/java.base/java/lang" }, + { "modules/java.base/java/lang" }, + { "/modules/java.base/java/lang/" }, + { "modules/java.base/java/lang/" } }; } @@ -208,23 +208,24 @@ public class Basic { private Object[][] pathPrefixes() { return new Object[][] { { "/" }, - { "java.base/java/lang" }, - { "./java.base/java/lang" }, - { "/java.base/java/lang" }, - { "/./java.base/java/lang" }, - { "java.base/java/lang/" }, - { "./java.base/java/lang/" }, - { "/./java.base/java/lang/" }, + { "modules/java.base/java/lang" }, + { "./modules/java.base/java/lang" }, + { "/modules/java.base/java/lang" }, + { "/./modules/java.base/java/lang" }, + { "modules/java.base/java/lang/" }, + { "./modules/java.base/java/lang/" }, + { "/./modules/java.base/java/lang/" }, }; } - @Test(dataProvider = "pathPrefixes") + // @Test(dataProvider = "pathPrefixes") public void testParentInDirList(String dir) throws Exception { FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); Path base = fs.getPath(dir); try (DirectoryStream stream = Files.newDirectoryStream(base)) { for (Path entry: stream) { - assertTrue( entry.getParent().equals(base) ); + assertTrue( entry.getParent().equals(base), + base.toString() + "-> " + entry.toString() ); } } } @@ -232,10 +233,10 @@ public class Basic { @DataProvider(name = "dirStreamStringFilterData") private Object[][] dirStreamStringFilterData() { return new Object[][] { - { "/java.base/java/lang", "/reflect" }, - { "/java.base/java/lang", "/Object.class" }, - { "/java.base/java/util", "/stream" }, - { "/java.base/java/util", "/List.class" }, + { "/modules/java.base/java/lang", "/reflect" }, + { "/modules/java.base/java/lang", "/Object.class" }, + { "/modules/java.base/java/util", "/stream" }, + { "/modules/java.base/java/util", "/List.class" }, }; } @@ -274,7 +275,7 @@ public class Basic { "isDirectory" }, { - "/java.base/java/lang", + "/modules/java.base/java/lang", (DirectoryStream.Filter)(Files::isRegularFile), "isFile" } @@ -322,7 +323,7 @@ public class Basic { FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); // This test assumes at least there are two elements in "java/lang" // package with any filter passed. don't change to different path here! - Path dir = fs.getPath("/java.base/java/lang"); + Path dir = fs.getPath("/modules/java.base/java/lang"); try (DirectoryStream stream = Files.newDirectoryStream(dir, filter)) { Iterator itr = stream.iterator(); itr.hasNext(); @@ -379,9 +380,9 @@ public class Basic { { "/META-INF" }, { "/META-INF/services" }, { "/META-INF/services/java.nio.file.spi.FileSystemProvider" }, - { "/java.base/packages.offsets" }, - { "/java.instrument/packages.offsets" }, - { "/jdk.zipfs/packages.offsets" }, + { "/modules/java.base/packages.offsets" }, + { "/modules/java.instrument/packages.offsets" }, + { "/modules/jdk.zipfs/packages.offsets" }, { "/java/lang" }, { "/java/util" }, }; @@ -396,20 +397,20 @@ public class Basic { @DataProvider(name = "pathGlobPatterns") private Object[][] pathGlobPatterns() { return new Object[][] { - { "/*", "/java.base", true }, - { "/*", "/java.base/java", false }, - { "/j*", "/java.base", true }, - { "/J*", "/java.base", false }, - { "**.class", "/java.base/java/lang/Object.class", true }, - { "**.java", "/java.base/java/lang/Object.class", false }, - { "**java/*", "/java.base/java/lang", true }, - { "**java/lang/ref*", "/java.base/java/lang/reflect", true }, - { "**java/lang/ref*", "/java.base/java/lang/ref", true }, - { "**java/lang/ref?", "/java.base/java/lang/ref", false }, - { "**java/lang/{ref,refl*}", "/java.base/java/lang/ref", true }, - { "**java/lang/{ref,refl*}", "/java.base/java/lang/reflect", true }, - { "**java/[a-u]?*/*.class", "/java.base/java/util/Map.class", true }, - { "**java/util/[a-z]*.class", "/java.base/java/util/TreeMap.class", false }, + { "/modules/*", "/modules/java.base", true }, + { "/modules/*", "/modules/java.base/java", false }, + { "/modules/j*", "/modules/java.base", true }, + { "/modules/J*", "/modules/java.base", false }, + { "**.class", "/modules/java.base/java/lang/Object.class", true }, + { "**.java", "/modules/java.base/java/lang/Object.class", false }, + { "**java/*", "/modules/java.base/java/lang", true }, + { "**java/lang/ref*", "/modules/java.base/java/lang/reflect", true }, + { "**java/lang/ref*", "/modules/java.base/java/lang/ref", true }, + { "**java/lang/ref?", "/modules/java.base/java/lang/ref", false }, + { "**java/lang/{ref,refl*}", "/modules/java.base/java/lang/ref", true }, + { "**java/lang/{ref,refl*}", "/modules/java.base/java/lang/reflect", true }, + { "**java/[a-u]?*/*.class", "/modules/java.base/java/util/Map.class", true }, + { "**java/util/[a-z]*.class", "/modules/java.base/java/util/TreeMap.class", false }, }; } @@ -428,20 +429,20 @@ public class Basic { @DataProvider(name = "pathRegexPatterns") private Object[][] pathRegexPatterns() { return new Object[][] { - { "/.*", "/java.base", true }, - { "/[^/]*", "/java.base/java", false }, - { "/j.*", "/java.base", true }, - { "/J.*", "/java.base", false }, - { ".*\\.class", "/java.base/java/lang/Object.class", true }, - { ".*\\.java", "/java.base/java/lang/Object.class", false }, - { ".*java/.*", "/java.base/java/lang", true }, - { ".*java/lang/ref.*", "/java.base/java/lang/reflect", true }, - { ".*java/lang/ref.*", "/java.base/java/lang/ref", true }, - { ".*/java/lang/ref.+", "/java.base/java/lang/ref", false }, - { ".*/java/lang/(ref|refl.*)", "/java.base/java/lang/ref", true }, - { ".*/java/lang/(ref|refl.*)", "/java.base/java/lang/reflect", true }, - { ".*/java/[a-u]?.*/.*\\.class", "/java.base/java/util/Map.class", true }, - { ".*/java/util/[a-z]*\\.class", "/java.base/java/util/TreeMap.class", false }, + { "/modules/.*", "/modules/java.base", true }, + { "/modules/[^/]*", "/modules/java.base/java", false }, + { "/modules/j.*", "/modules/java.base", true }, + { "/modules/J.*", "/modules/java.base", false }, + { ".*\\.class", "/modules/java.base/java/lang/Object.class", true }, + { ".*\\.java", "/modules/java.base/java/lang/Object.class", false }, + { ".*java/.*", "/modules/java.base/java/lang", true }, + { ".*java/lang/ref.*", "/modules/java.base/java/lang/reflect", true }, + { ".*java/lang/ref.*", "/modules/java.base/java/lang/ref", true }, + { ".*/java/lang/ref.+", "/modules/java.base/java/lang/ref", false }, + { ".*/java/lang/(ref|refl.*)", "/modules/java.base/java/lang/ref", true }, + { ".*/java/lang/(ref|refl.*)", "/modules/java.base/java/lang/reflect", true }, + { ".*/java/[a-u]?.*/.*\\.class", "/modules/java.base/java/util/Map.class", true }, + { ".*/java/util/[a-z]*\\.class", "/modules/java.base/java/util/TreeMap.class", false }, }; } @@ -456,4 +457,159 @@ public class Basic { p + (expectMatch? " should match " : " should not match ") + pattern); } + + @Test + public void testPackagesAndModules() throws Exception { + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + assertTrue(Files.isDirectory(fs.getPath("/packages"))); + assertTrue(Files.isDirectory(fs.getPath("/modules"))); + } + + @DataProvider(name = "packagesSubDirs") + private Object[][] packagesSubDirs() { + return new Object[][] { + { "java.lang" }, + { "java.util" }, + { "java.nio" }, + { "jdk.nashorn.api.scripting" } + }; + } + + @Test(dataProvider = "packagesSubDirs") + public void testPackagesSubDirs(String pkg) throws Exception { + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + assertTrue(Files.isDirectory(fs.getPath("/packages/" + pkg)), + pkg + " missing"); + } + + @DataProvider(name = "packagesLinks") + private Object[][] packagesLinks() { + return new Object[][] { + { "/packages/java.lang/java.base" }, + { "/packages/java.lang/java.instrument" }, + { "/packages/java/java.base" }, + { "/packages/java/java.instrument" }, + { "/packages/java/java.rmi" }, + { "/packages/java/java.sql" }, + { "/packages/javax/java.base" }, + { "/packages/javax/java.sql" }, + { "/packages/javax/java.xml" }, + { "/packages/javax/java.management" }, + { "/packages/java.util/java.base" }, + { "/packages/jdk.nashorn.api.scripting/jdk.scripting.nashorn" }, + }; + } + + @Test(dataProvider = "packagesLinks") + public void testPackagesLinks(String link) throws Exception { + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + Path path = fs.getPath(link); + assertTrue(Files.exists(path), link + " missing"); + assertTrue(Files.isSymbolicLink(path), path + " is not a link"); + path = Files.readSymbolicLink(path); + assertEquals(path.toString(), "/modules" + link.substring(link.lastIndexOf("/"))); + } + + @DataProvider(name = "modulesSubDirs") + private Object[][] modulesSubDirs() { + return new Object[][] { + { "java.base" }, + { "java.sql" }, + { "jdk.scripting.nashorn" }, + }; + } + + @Test(dataProvider = "modulesSubDirs") + public void testModulesSubDirs(String module) throws Exception { + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + Path path = fs.getPath("/modules/" + module); + assertTrue(Files.isDirectory(path), module + " missing"); + assertTrue(!Files.isSymbolicLink(path), path + " is a link"); + } + + @DataProvider(name="linkChases") + private Object[][] linkChases() { + return new Object[][] { + { "/modules/java.base/java/lang" }, + { "/modules/java.base/java/util/Vector.class" }, + { "/modules/jdk.scripting.nashorn/jdk/nashorn" }, + { "/packages/java.lang/java.base/java/lang" }, + { "/packages/java.util/java.base/java/util/Vector.class" }, + }; + } + + @Test(dataProvider = "linkChases") + public void testLinkChases(String link) throws Exception { + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + Path path = fs.getPath(link); + assertTrue(Files.exists(path), link); + } + + @Test + public void testSymlinkDirList() throws Exception { + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + Path path = fs.getPath("/packages/java.lang/java.base"); + assertTrue(Files.isSymbolicLink(path)); + assertTrue(Files.isDirectory(path)); + + boolean javaSeen = false, javaxSeen = false; + try (DirectoryStream stream = Files.newDirectoryStream(path)) { + for (Path p : stream) { + String str = p.toString(); + if (str.endsWith("/java")) { + javaSeen = true; + } else if (str.endsWith("javax")) { + javaxSeen = true; + } + } + } + assertTrue(javaSeen); + assertTrue(javaxSeen); + } + + @Test + public void testPackagesSubDirList() throws Exception { + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + String pathName = "/packages/javax.annotation"; + Path path = fs.getPath(pathName); + boolean seenJavaCompiler = false, seenAnnotationsCommon = false; + try (DirectoryStream stream = Files.newDirectoryStream(path)) { + for (Path p : stream) { + String str = p.toString(); + if (str.equals(pathName + "/java.compiler")) { + seenJavaCompiler = true; + } else if (str.equals(pathName + "/java.annotations.common")) { + seenAnnotationsCommon = true; + } + } + } + assertTrue(seenJavaCompiler); + assertTrue(seenAnnotationsCommon); + } + + @Test + public void testRootDirList() throws Exception { + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + Path path = fs.getPath("/"); + // check /packages and /modules are not repeated + // and seen once. + boolean packages = false, modules = false; + try (DirectoryStream stream = Files.newDirectoryStream(path)) { + for (Path p : stream) { + String str = p.toString(); + switch (str) { + case "/packages": + assertFalse(packages, "/packages repeated"); + packages = true; + break; + case "/modules": + assertFalse(modules, "/modules repeated"); + modules = true; + break; + } + } + } + assertTrue(packages, "/packages missing in / list!"); + assertTrue(modules, "/modules missing in / list!"); + } } diff --git a/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java b/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java index 4e094acac38..f6d111475ef 100644 --- a/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java +++ b/jdk/test/jdk/internal/jrtfs/WithSecurityManager.java @@ -55,7 +55,8 @@ public class WithSecurityManager { FileSystems.getFileSystem(URI.create("jrt:/")); if (!allow) throw new RuntimeException("access not expected"); } catch (SecurityException se) { - if (allow) throw new RuntimeException("access expected"); + if (allow) + throw se; } // check FileSystems.newFileSystem @@ -63,7 +64,8 @@ public class WithSecurityManager { FileSystems.newFileSystem(URI.create("jrt:/"), null); if (!allow) throw new RuntimeException("access not expected"); } catch (SecurityException se) { - if (allow) throw new RuntimeException("access expected"); + if (allow) + throw se; } // check Paths.get @@ -71,7 +73,8 @@ public class WithSecurityManager { Paths.get(URI.create("jrt:/java.base/java/lang/Object.class")); if (!allow) throw new RuntimeException("access not expected"); } catch (SecurityException se) { - if (allow) throw new RuntimeException("access expected"); + if (allow) + throw se; } } } From a47dc46f90cf1f74c08865fb6a1dde703a07b831 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Thu, 25 Jun 2015 11:18:04 +0200 Subject: [PATCH 06/21] 8071487: javax/management/monitor/GaugeMonitorDeadlockTest.java timed out Reviewed-by: dholmes --- .../management/monitor/GaugeMonitorDeadlockTest.java | 9 ++++++--- .../management/monitor/StringMonitorDeadlockTest.java | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/jdk/test/javax/management/monitor/GaugeMonitorDeadlockTest.java b/jdk/test/javax/management/monitor/GaugeMonitorDeadlockTest.java index a8a51c39ad7..4f50b41a756 100644 --- a/jdk/test/javax/management/monitor/GaugeMonitorDeadlockTest.java +++ b/jdk/test/javax/management/monitor/GaugeMonitorDeadlockTest.java @@ -27,6 +27,7 @@ * @summary Test that no locks are held when a monitor attribute is sampled * or notif delivered. * @author Eamonn McManus + * @library /lib/testlibrary * @modules java.management * @run clean GaugeMonitorDeadlockTest * @run build GaugeMonitorDeadlockTest @@ -48,6 +49,8 @@ import javax.management.ObjectName; import javax.management.monitor.GaugeMonitor; import javax.management.monitor.GaugeMonitorMBean; +import jdk.testlibrary.Utils; + public class GaugeMonitorDeadlockTest { private static enum When {IN_GET_ATTRIBUTE, IN_NOTIFY}; private static long checkingTime; @@ -55,8 +58,7 @@ public class GaugeMonitorDeadlockTest { public static void main(String[] args) throws Exception { if (args.length != 1) throw new Exception("Arg should be test number"); - double factor = Double.parseDouble(System.getProperty("test.timeout.factor", "1.0")); - checkingTime = (long)factor*1000; + checkingTime = Utils.adjustTimeout(1000); // default 1s timeout System.out.println("=== checkingTime = " + checkingTime + "ms"); int testNo = Integer.parseInt(args[0]) - 1; @@ -102,11 +104,12 @@ public class GaugeMonitorDeadlockTest { monitorProxy.setGranularityPeriod(10L); // 10 ms monitorProxy.setNotifyHigh(true); monitorProxy.setNotifyLow(true); - monitorProxy.start(); System.out.println("=== Waiting observedProxy.getGetCount() to be " + "changed, presumable deadlock if timeout?"); final int initGetCount = observedProxy.getGetCount(); + monitorProxy.start(); + long checkedTime = System.currentTimeMillis(); long nowTime; ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); diff --git a/jdk/test/javax/management/monitor/StringMonitorDeadlockTest.java b/jdk/test/javax/management/monitor/StringMonitorDeadlockTest.java index cede5465804..7f016bb673b 100644 --- a/jdk/test/javax/management/monitor/StringMonitorDeadlockTest.java +++ b/jdk/test/javax/management/monitor/StringMonitorDeadlockTest.java @@ -38,7 +38,6 @@ import java.lang.management.ManagementFactory; import java.util.concurrent.atomic.AtomicInteger; -import javax.management.Attribute; import javax.management.JMX; import javax.management.MBeanServer; import javax.management.Notification; @@ -96,9 +95,10 @@ public class StringMonitorDeadlockTest { monitorProxy.setStringToCompare("old"); monitorProxy.setGranularityPeriod(10L); // 10 ms monitorProxy.setNotifyDiffer(true); - monitorProxy.start(); final int initGetCount = observedProxy.getGetCount(); + monitorProxy.start(); + int getCount = initGetCount; for (int i = 0; i < 500; i++) { // 500 * 10 = 5 seconds getCount = observedProxy.getGetCount(); From 9f34fe51a851e0234977ff7c21fc9026e110b9b9 Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Thu, 25 Jun 2015 15:16:55 +0300 Subject: [PATCH 07/21] 8080993: Compilation errors with recent clang in awt_parseImage.c and splashscreen_sys.m Reviewed-by: azvegint, bae --- .../macosx/native/libsplashscreen/splashscreen_sys.m | 1 - .../java.desktop/share/native/libawt/awt/image/awt_parseImage.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/jdk/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m b/jdk/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m index 07bbd43e0a5..7235367bf60 100644 --- a/jdk/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m +++ b/jdk/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m @@ -275,7 +275,6 @@ SplashRedrawWindow(Splash * splash) { [image addRepresentation: rep]; float scaleFactor = splash->scaleFactor; if (scaleFactor > 0 && scaleFactor != 1) { - [image setScalesWhenResized:YES]; NSSize size = [image size]; size.width /= scaleFactor; size.height /= scaleFactor; diff --git a/jdk/src/java.desktop/share/native/libawt/awt/image/awt_parseImage.c b/jdk/src/java.desktop/share/native/libawt/awt/image/awt_parseImage.c index 882c799efc4..4b6b24183be 100644 --- a/jdk/src/java.desktop/share/native/libawt/awt/image/awt_parseImage.c +++ b/jdk/src/java.desktop/share/native/libawt/awt/image/awt_parseImage.c @@ -852,7 +852,7 @@ setHints(JNIEnv *env, BufImageS_t *imageP) { hintP->needToExpand = TRUE; hintP->expandToNbits = cmodelP->maxNbits; } - else if (rasterP->sppsm.offsets != NULL) { + else { for (i=0; i < rasterP->numBands; i++) { if (!(rasterP->sppsm.offsets[i] % 8)) { hintP->needToExpand = TRUE; From 561c4e223c6795dfd180f19cec56c74cb2db2440 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 26 Jun 2015 12:38:39 +0300 Subject: [PATCH 08/21] 8014241: Clean up unused JNI fields and methods in imageInitIDs.h Reviewed-by: azvegint, prr --- jdk/make/mapfiles/libawt/mapfile-vers | 2 -- jdk/make/mapfiles/libawt/mapfile-vers-linux | 2 -- .../java/awt/image/ComponentSampleModel.java | 8 +------ .../native/libawt/awt/image/imageInitIDs.c | 23 +------------------ .../native/libawt/awt/image/imageInitIDs.h | 19 +-------------- 5 files changed, 3 insertions(+), 51 deletions(-) diff --git a/jdk/make/mapfiles/libawt/mapfile-vers b/jdk/make/mapfiles/libawt/mapfile-vers index 636c255c6c6..4624977e75c 100644 --- a/jdk/make/mapfiles/libawt/mapfile-vers +++ b/jdk/make/mapfiles/libawt/mapfile-vers @@ -37,7 +37,6 @@ SUNWprivate_1.1 { Java_sun_awt_image_DataBufferNative_getElem; Java_sun_awt_image_DataBufferNative_setElem; Java_java_awt_image_ColorModel_initIDs; - Java_java_awt_image_ComponentSampleModel_initIDs; Java_java_awt_image_IndexColorModel_initIDs; Java_java_awt_image_Kernel_initIDs; Java_java_awt_image_Raster_initIDs; @@ -89,7 +88,6 @@ SUNWprivate_1.1 { Java_java_awt_Choice_initIDs; Java_java_awt_Dimension_initIDs; Java_java_awt_event_MouseEvent_initIDs; - Java_java_awt_image_DataBufferInt_initIDs; Java_java_awt_image_SinglePixelPackedSampleModel_initIDs; Java_java_awt_Rectangle_initIDs; Java_sun_awt_image_BufImgSurfaceData_initIDs; diff --git a/jdk/make/mapfiles/libawt/mapfile-vers-linux b/jdk/make/mapfiles/libawt/mapfile-vers-linux index 5624693fcca..81f5f037e51 100644 --- a/jdk/make/mapfiles/libawt/mapfile-vers-linux +++ b/jdk/make/mapfiles/libawt/mapfile-vers-linux @@ -37,7 +37,6 @@ SUNWprivate_1.1 { Java_sun_awt_image_DataBufferNative_getElem; Java_sun_awt_image_DataBufferNative_setElem; Java_java_awt_image_ColorModel_initIDs; - Java_java_awt_image_ComponentSampleModel_initIDs; Java_java_awt_image_IndexColorModel_initIDs; Java_java_awt_image_Kernel_initIDs; Java_java_awt_image_Raster_initIDs; @@ -89,7 +88,6 @@ SUNWprivate_1.1 { Java_java_awt_Choice_initIDs; Java_java_awt_Dimension_initIDs; Java_java_awt_event_MouseEvent_initIDs; - Java_java_awt_image_DataBufferInt_initIDs; Java_java_awt_image_SinglePixelPackedSampleModel_initIDs; Java_java_awt_Rectangle_initIDs; Java_sun_awt_image_BufImgSurfaceData_getSurfaceData; diff --git a/jdk/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java b/jdk/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java index d6706b6c610..fc480701eac 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java +++ b/jdk/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * 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,12 +104,6 @@ public class ComponentSampleModel extends SampleModel */ protected int pixelStride; - static private native void initIDs(); - static { - ColorModel.loadLibraries(); - initIDs(); - } - /** * Constructs a ComponentSampleModel with the specified parameters. * The number of bands will be given by the length of the bandOffsets array. diff --git a/jdk/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.c b/jdk/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.c index f7fe035fe1e..dbb2c1127bd 100644 --- a/jdk/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.c +++ b/jdk/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * 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,8 +45,6 @@ Java_java_awt_image_Raster_initIDs(JNIEnv *env, jclass cls) { CHECK_NULL(g_RasterWidthID = (*env)->GetFieldID(env, cls, "width", "I")); CHECK_NULL(g_RasterHeightID = (*env)->GetFieldID(env, cls, "height", "I")); CHECK_NULL(g_RasterNumBandsID = (*env)->GetFieldID(env, cls, "numBands", "I")); - CHECK_NULL(g_RasterGetDataMID = (*env)->GetMethodID(env, cls, "getDataElements", - "(IIIILjava/lang/Object;)Ljava/lang/Object;")); CHECK_NULL(g_RasterMinXID = (*env)->GetFieldID(env, cls, "minX", "I")); CHECK_NULL(g_RasterMinYID = (*env)->GetFieldID(env, cls, "minY", "I")); CHECK_NULL(g_RasterBaseOriginXID = (*env)->GetFieldID(env, cls, @@ -67,7 +65,6 @@ Java_sun_awt_image_ByteComponentRaster_initIDs(JNIEnv *env, jclass cls) { CHECK_NULL(g_BCRdataID = (*env)->GetFieldID(env, cls, "data", "[B")); CHECK_NULL(g_BCRscanstrID = (*env)->GetFieldID(env, cls, "scanlineStride", "I")); CHECK_NULL(g_BCRpixstrID = (*env)->GetFieldID(env, cls, "pixelStride", "I")); - CHECK_NULL(g_BCRbandoffsID = (*env)->GetFieldID(env, cls, "bandOffset", "I")); CHECK_NULL(g_BCRdataOffsetsID = (*env)->GetFieldID(env, cls, "dataOffsets", "[I")); CHECK_NULL(g_BCRtypeID = (*env)->GetFieldID(env, cls, "type", "I")); } @@ -86,7 +83,6 @@ Java_sun_awt_image_ShortComponentRaster_initIDs(JNIEnv *env, jclass cls) { CHECK_NULL(g_SCRdataID = (*env)->GetFieldID(env, cls, "data", "[S")); CHECK_NULL(g_SCRscanstrID = (*env)->GetFieldID(env, cls, "scanlineStride", "I")); CHECK_NULL(g_SCRpixstrID = (*env)->GetFieldID(env, cls, "pixelStride", "I")); - CHECK_NULL(g_SCRbandoffsID = (*env)->GetFieldID(env, cls, "bandOffset", "I")); CHECK_NULL(g_SCRdataOffsetsID = (*env)->GetFieldID(env, cls, "dataOffsets", "[I")); CHECK_NULL(g_SCRtypeID = (*env)->GetFieldID(env, cls, "type", "I")); } @@ -96,9 +92,6 @@ Java_sun_awt_image_IntegerComponentRaster_initIDs(JNIEnv *env, jclass cls) { CHECK_NULL(g_ICRscanstrID = (*env)->GetFieldID(env, cls, "scanlineStride", "I")); CHECK_NULL(g_ICRpixstrID = (*env)->GetFieldID(env, cls, "pixelStride", "I")); CHECK_NULL(g_ICRdataOffsetsID = (*env)->GetFieldID(env, cls, "dataOffsets", "[I")); - CHECK_NULL(g_ICRbandoffsID = (*env)->GetFieldID(env, cls, "bandOffset", "I")); - CHECK_NULL(g_ICRputDataMID = (*env)->GetMethodID(env, cls, "setDataElements", - "(IIIILjava/lang/Object;)V")); CHECK_NULL(g_ICRtypeID = (*env)->GetFieldID(env, cls, "type", "I")); } @@ -121,8 +114,6 @@ Java_java_awt_image_ColorModel_initIDs(JNIEnv *env, jclass cls) { CHECK_NULL(g_CMisAlphaPreID = (*env)->GetFieldID(env, cls, "isAlphaPremultiplied", "Z")); CHECK_NULL(g_CMtransparencyID = (*env)->GetFieldID(env, cls, "transparency", "I")); - CHECK_NULL(g_CMgetRGBMID = (*env)->GetMethodID(env, cls, "getRGB", - "(Ljava/lang/Object;)I")); CHECK_NULL(g_CMcsTypeID = (*env)->GetFieldID(env, cls, "colorSpaceType", "I")); CHECK_NULL(g_CMis_sRGBID = (*env)->GetFieldID(env, cls, "is_sRGB", "Z")); CHECK_NULL(g_CMgetRGBdefaultMID = (*env)->GetStaticMethodID(env, cls, @@ -147,21 +138,9 @@ Java_java_awt_image_SampleModel_initIDs(JNIEnv *env, jclass cls) { "(IIII[ILjava/awt/image/DataBuffer;)V")); } -JNIEXPORT void JNICALL -Java_java_awt_image_ComponentSampleModel_initIDs(JNIEnv *env, jclass cls) { - CHECK_NULL(g_CSMPixStrideID = (*env)->GetFieldID(env, cls, "pixelStride", "I")); - CHECK_NULL(g_CSMScanStrideID = (*env)->GetFieldID(env, cls, "scanlineStride", "I")); - CHECK_NULL(g_CSMBandOffsetsID = (*env)->GetFieldID(env, cls, "bandOffsets", "[I")); -} - JNIEXPORT void JNICALL Java_java_awt_image_Kernel_initIDs(JNIEnv *env, jclass cls) { CHECK_NULL(g_KernelWidthID = (*env)->GetFieldID(env, cls, "width", "I")); CHECK_NULL(g_KernelHeightID = (*env)->GetFieldID(env, cls, "height", "I")); CHECK_NULL(g_KernelDataID = (*env)->GetFieldID(env, cls, "data", "[F")); } - -JNIEXPORT void JNICALL -Java_java_awt_image_DataBufferInt_initIDs(JNIEnv *env, jclass cls) { - CHECK_NULL(g_DataBufferIntPdataID = (*env)->GetFieldID(env, cls, "pData", "J")); -} diff --git a/jdk/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.h b/jdk/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.h index 9b9356c8a74..f2a7e0da251 100644 --- a/jdk/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.h +++ b/jdk/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,6 @@ IMGEXTERN jmethodID g_BImgSetRGBMID; /* Raster ids */ IMGEXTERN jfieldID g_RasterWidthID; IMGEXTERN jfieldID g_RasterHeightID; -IMGEXTERN jfieldID g_RasterNumBandsID; IMGEXTERN jfieldID g_RasterBaseRasterID; IMGEXTERN jfieldID g_RasterMinXID; IMGEXTERN jfieldID g_RasterMinYID; @@ -52,12 +51,10 @@ IMGEXTERN jfieldID g_RasterSampleModelID; IMGEXTERN jfieldID g_RasterDataBufferID; IMGEXTERN jfieldID g_RasterNumDataElementsID; IMGEXTERN jfieldID g_RasterNumBandsID; -IMGEXTERN jmethodID g_RasterGetDataMID; IMGEXTERN jfieldID g_BCRdataID; IMGEXTERN jfieldID g_BCRscanstrID; IMGEXTERN jfieldID g_BCRpixstrID; -IMGEXTERN jfieldID g_BCRbandoffsID; IMGEXTERN jfieldID g_BCRdataOffsetsID; IMGEXTERN jfieldID g_BCRtypeID; IMGEXTERN jfieldID g_BPRdataID; @@ -68,16 +65,13 @@ IMGEXTERN jfieldID g_BPRdataBitOffsetID; IMGEXTERN jfieldID g_SCRdataID; IMGEXTERN jfieldID g_SCRscanstrID; IMGEXTERN jfieldID g_SCRpixstrID; -IMGEXTERN jfieldID g_SCRbandoffsID; IMGEXTERN jfieldID g_SCRdataOffsetsID; IMGEXTERN jfieldID g_SCRtypeID; IMGEXTERN jfieldID g_ICRdataID; IMGEXTERN jfieldID g_ICRscanstrID; IMGEXTERN jfieldID g_ICRpixstrID; -IMGEXTERN jfieldID g_ICRbandoffsID; IMGEXTERN jfieldID g_ICRdataOffsetsID; IMGEXTERN jfieldID g_ICRtypeID; -IMGEXTERN jmethodID g_ICRputDataMID; /* Color Model ids */ IMGEXTERN jfieldID g_CMpDataID; @@ -87,7 +81,6 @@ IMGEXTERN jfieldID g_CMnumComponentsID; IMGEXTERN jfieldID g_CMsuppAlphaID; IMGEXTERN jfieldID g_CMisAlphaPreID; IMGEXTERN jfieldID g_CMtransparencyID; -IMGEXTERN jmethodID g_CMgetRGBMID; IMGEXTERN jfieldID g_CMcsTypeID; IMGEXTERN jfieldID g_CMis_sRGBID; IMGEXTERN jmethodID g_CMgetRGBdefaultMID; @@ -108,19 +101,9 @@ IMGEXTERN jfieldID g_SPPSMmaskOffID; IMGEXTERN jfieldID g_SPPSMnBitsID; IMGEXTERN jfieldID g_SPPSMmaxBitID; -/* Component Sample Model ids */ -IMGEXTERN jfieldID g_CSMPixStrideID; -IMGEXTERN jfieldID g_CSMScanStrideID; -IMGEXTERN jfieldID g_CSMBandOffsetsID; - /* Kernel ids */ IMGEXTERN jfieldID g_KernelWidthID; IMGEXTERN jfieldID g_KernelHeightID; -IMGEXTERN jfieldID g_KernelXOriginID; -IMGEXTERN jfieldID g_KernelYOriginD; IMGEXTERN jfieldID g_KernelDataID; -/* DataBufferInt ids */ -IMGEXTERN jfieldID g_DataBufferIntPdataID; - #endif /* IMAGEINITIDS_H */ From 33c5b92bc69af16581d91e8e71fb8822ea89f84d Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Mon, 29 Jun 2015 01:27:08 +0300 Subject: [PATCH 09/21] 8080405: Exception in thread "AWT-EventQueue-1" java.security.AccessControlException Reviewed-by: prr, chegar, art --- .../classes/sun/misc/ManagedLocalsThread.java | 7 +- .../com/apple/laf/AquaFileSystemModel.java | 8 +- .../macosx/classes/sun/font/CFontManager.java | 21 ++-- .../macosx/classes/sun/lwawt/LWToolkit.java | 19 +--- .../lwawt/macosx/CDragSourceContextPeer.java | 8 +- .../classes/sun/lwawt/macosx/CFileDialog.java | 8 +- .../sun/lwawt/macosx/CPrinterDialogPeer.java | 6 +- .../classes/sun/lwawt/macosx/CPrinterJob.java | 11 +- .../com/sun/imageio/stream/StreamCloser.java | 22 ++-- .../plaf/windows/WindowsLookAndFeel.java | 8 +- .../sun/media/sound/JSSecurityManager.java | 10 +- .../com/sun/media/sound/SoftAudioPusher.java | 8 +- .../sun/media/sound/SoftJitterCorrector.java | 8 +- .../com/sun/media/sound/SoftSynthesizer.java | 8 +- .../classes/java/awt/EventDispatchThread.java | 4 +- .../renderable/RenderableImageProducer.java | 9 +- .../share/classes/javax/swing/JTable.java | 7 +- .../share/classes/javax/swing/TimerQueue.java | 13 +-- .../swing/plaf/basic/BasicDirectoryModel.java | 6 +- .../javax/swing/text/JTextComponent.java | 6 +- .../classes/javax/swing/text/LayoutQueue.java | 7 +- .../classes/sun/applet/AppletClassLoader.java | 4 +- .../classes/sun/awt/AWTAutoShutdown.java | 13 +-- .../share/classes/sun/awt/AppContext.java | 14 +-- .../sun/awt/im/InputMethodManager.java | 9 +- .../classes/sun/awt/image/ImageFetcher.java | 4 +- .../classes/sun/font/CreatedFontTracker.java | 22 ++-- .../classes/sun/font/SunFontManager.java | 12 +- .../share/classes/sun/java2d/Disposer.java | 13 +-- .../sun/java2d/loops/GraphicsPrimitive.java | 12 +- .../sun/java2d/opengl/OGLRenderQueue.java | 7 +- .../share/classes/sun/print/PrintJob2D.java | 9 +- .../classes/sun/print/ServiceNotifier.java | 4 +- .../sun/awt/X11/GtkFileDialogPeer.java | 9 +- .../unix/classes/sun/awt/X11/InfoWindow.java | 9 +- .../unix/classes/sun/awt/X11/XToolkit.java | 16 +-- .../classes/sun/awt/X11GraphicsDevice.java | 10 +- .../sun/print/PrintServiceLookupProvider.java | 9 +- .../awt/shell/Win32ShellFolderManager2.java | 28 ++--- .../sun/awt/windows/WFileDialogPeer.java | 8 +- .../sun/awt/windows/WPageDialogPeer.java | 8 +- .../sun/awt/windows/WPrintDialogPeer.java | 8 +- .../classes/sun/awt/windows/WToolkit.java | 19 +--- .../java2d/d3d/D3DScreenUpdateManager.java | 20 +--- .../sun/print/PrintServiceLookupProvider.java | 9 +- .../PropertyPermissionOnEDT.java | 105 ++++++++++++++++++ .../PropertyPermissionOnEDT/java.policy | 4 + 47 files changed, 251 insertions(+), 338 deletions(-) create mode 100644 jdk/test/java/awt/EventDispatchThread/PropertyPermissionOnEDT/PropertyPermissionOnEDT.java create mode 100644 jdk/test/java/awt/EventDispatchThread/PropertyPermissionOnEDT/java.policy diff --git a/jdk/src/java.base/share/classes/sun/misc/ManagedLocalsThread.java b/jdk/src/java.base/share/classes/sun/misc/ManagedLocalsThread.java index cd75ef237ce..f520ca384b6 100644 --- a/jdk/src/java.base/share/classes/sun/misc/ManagedLocalsThread.java +++ b/jdk/src/java.base/share/classes/sun/misc/ManagedLocalsThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * 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,11 @@ public class ManagedLocalsThread extends Thread { eraseThreadLocals(); } + public ManagedLocalsThread(ThreadGroup group, Runnable target) { + super(group, target); + eraseThreadLocals(); + } + public ManagedLocalsThread(Runnable target, String name) { super(target, name); eraseThreadLocals(); diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java index 7aa82f51a9e..266d5065ca3 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -383,11 +383,7 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi this.currentDirectory = currentDirectory; this.fid = fid; String name = "Aqua L&F File Loading Thread"; - if (System.getSecurityManager() == null) { - this.loadThread = new Thread(FilesLoader.this, name); - } else { - this.loadThread = new ManagedLocalsThread(FilesLoader.this, name); - } + this.loadThread = new ManagedLocalsThread(this, name); this.loadThread.start(); } diff --git a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java index 341af9ff347..d152a5f01c0 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java +++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ import sun.awt.FontConfiguration; import sun.awt.HeadlessToolkit; import sun.awt.util.ThreadGroupUtils; import sun.lwawt.macosx.*; -import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; public final class CFontManager extends SunFontManager { private static Hashtable genericFonts = new Hashtable(); @@ -213,17 +213,12 @@ public final class CFontManager extends SunFontManager { } }; AccessController.doPrivileged((PrivilegedAction) () -> { - if (System.getSecurityManager() == null) { - /* The thread must be a member of a thread group - * which will not get GCed before VM exit. - * Make its parent the top-level thread group. - */ - ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - fileCloser = new Thread(rootTG, fileCloserRunnable); - } else { - /* InnocuousThread is a member of a correct TG by default */ - fileCloser = new InnocuousThread(fileCloserRunnable); - } + /* The thread must be a member of a thread group + * which will not get GCed before VM exit. + * Make its parent the top-level thread group. + */ + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + fileCloser = new ManagedLocalsThread(rootTG, fileCloserRunnable); fileCloser.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(fileCloser); return null; diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java index 4ab5c410830..44136640ccf 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java @@ -35,7 +35,7 @@ import java.security.*; import java.util.*; import sun.awt.*; -import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; import sun.print.*; import sun.awt.util.ThreadGroupUtils; @@ -77,22 +77,13 @@ public abstract class LWToolkit extends SunToolkit implements Runnable { shutdown(); waitForRunState(STATE_CLEANUP); }; - Thread shutdown; - if (System.getSecurityManager() == null) { - shutdown = new Thread(ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); - } else { - shutdown = new InnocuousThread(shutdownRunnable); - } + Thread shutdown = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); shutdown.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdown); - String name = "AWT-LW"; - Thread toolkitThread; - if (System.getSecurityManager() == null) { - toolkitThread = new Thread(ThreadGroupUtils.getRootThreadGroup(), LWToolkit.this, name); - } else { - toolkitThread = new InnocuousThread(LWToolkit.this, name); - } + Thread toolkitThread = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), this, name); toolkitThread.setDaemon(true); toolkitThread.setPriority(Thread.NORM_PRIORITY + 1); toolkitThread.start(); diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java index af5c59d420c..10aef016b0c 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java @@ -181,13 +181,7 @@ public final class CDragSourceContextPeer extends SunDragSourceContextPeer { } } }; - Thread dragThread; - if (System.getSecurityManager() == null) { - dragThread = new Thread(dragRunnable); - } else { - dragThread = new ManagedLocalsThread(dragRunnable); - } - dragThread.start(); + new ManagedLocalsThread(dragRunnable).start(); } catch (Exception e) { final long nativeDragSource = getNativeContext(); setNativeContext(0); diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java index 0e8ee1e1fc4..459afae179d 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * 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,11 +120,7 @@ class CFileDialog implements FileDialogPeer { if (visible) { // Java2 Dialog class requires peer to run code in a separate thread // and handles keeping the call modal - if (System.getSecurityManager() == null) { - new Thread(new Task()).start(); - } else { - new ManagedLocalsThread(new Task()).start(); - } + new ManagedLocalsThread(new Task()).start(); } // We hide ourself before "show" returns - setVisible(false) // doesn't apply diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java index 6ff3ec01e0e..1837feb0ccd 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java @@ -59,11 +59,7 @@ public class CPrinterDialogPeer extends LWWindowPeer { printerDialog.setRetVal(printerDialog.showDialog()); printerDialog.setVisible(false); }; - if (System.getSecurityManager() == null) { - new Thread(task).start(); - } else { - new ManagedLocalsThread(task).start(); - } + new ManagedLocalsThread(task).start(); } } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index 4dba1d221e3..a7b200981ed 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -736,12 +736,7 @@ public final class CPrinterJob extends RasterPrinterJob { // upcall from native private static void detachPrintLoop(final long target, final long arg) { - Runnable task = () -> _safePrintLoop(target, arg); - if (System.getSecurityManager() == null) { - new Thread(task).start(); - } else { - new ManagedLocalsThread(task).start(); - } + new ManagedLocalsThread(() -> _safePrintLoop(target, arg)).start(); } private static native void _safePrintLoop(long target, long arg); @@ -779,4 +774,4 @@ public final class CPrinterJob extends RasterPrinterJob { (float) (paper.getImageableHeight() / dpi), MediaPrintableArea.INCH); } -} \ No newline at end of file +} diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java index b660f272e2c..32fa02fe175 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ package com.sun.imageio.stream; import sun.awt.util.ThreadGroupUtils; -import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; import java.io.IOException; import java.security.AccessController; @@ -87,17 +87,13 @@ public class StreamCloser { }; AccessController.doPrivileged((PrivilegedAction) () -> { - if (System.getSecurityManager() == null) { - /* The thread must be a member of a thread group - * which will not get GCed before VM exit. - * Make its parent the top-level thread group. - */ - ThreadGroup tg = ThreadGroupUtils.getRootThreadGroup(); - streamCloser = new Thread(tg, streamCloserRunnable); - } else { - /* InnocuousThread is a member of a correct TG by default */ - streamCloser = new InnocuousThread(streamCloserRunnable); - } + /* The thread must be a member of a thread group + * which will not get GCed before VM exit. + * Make its parent the top-level thread group. + */ + ThreadGroup tg = ThreadGroupUtils.getRootThreadGroup(); + streamCloser = new ManagedLocalsThread(tg, + streamCloserRunnable); /* Set context class loader to null in order to avoid * keeping a strong reference to an application classloader. */ diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java index 0a666b12e25..6d379435397 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2038,11 +2038,7 @@ public class WindowsLookAndFeel extends BasicLookAndFeel if (audioRunnable != null) { // Runnable appears to block until completed playing, hence // start up another thread to handle playing. - if (System.getSecurityManager() == null) { - new Thread(audioRunnable).start(); - } else { - new ManagedLocalsThread(audioRunnable).start(); - } + new ManagedLocalsThread(audioRunnable).start(); } } } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java index 63eaba1c4ec..738704facf4 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * 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 com.sun.media.sound; -import sun.misc.InnocuousThread; import sun.misc.ManagedLocalsThread; import java.io.BufferedInputStream; @@ -147,12 +146,7 @@ final class JSSecurityManager { final String threadName, final boolean isDaemon, final int priority, final boolean doStart) { - Thread thread; - if (System.getSecurityManager() == null) { - thread = new Thread(runnable); - } else { - thread = new ManagedLocalsThread(runnable); - } + Thread thread = new ManagedLocalsThread(runnable); if (threadName != null) { thread.setName(threadName); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java index a5fdd4e9f86..87f4852714c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. * 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,11 +55,7 @@ public final class SoftAudioPusher implements Runnable { if (active) return; active = true; - if (System.getSecurityManager() == null) { - audiothread = new Thread(this); - } else { - audiothread = new ManagedLocalsThread(this); - } + audiothread = new ManagedLocalsThread(this); audiothread.setDaemon(true); audiothread.setPriority(Thread.MAX_PRIORITY); audiothread.start(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java index 85c615e1801..f845a369e0b 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -216,11 +216,7 @@ public final class SoftJitterCorrector extends AudioInputStream { } }; - if (System.getSecurityManager() == null) { - thread = new Thread(runnable); - } else { - thread = new ManagedLocalsThread(runnable); - } + thread = new ManagedLocalsThread(runnable); thread.setDaemon(true); thread.setPriority(Thread.MAX_PRIORITY); thread.start(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java index 81c33ff788b..b888742970f 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,11 +141,7 @@ public final class SoftSynthesizer implements AudioSynthesizer, pusher = null; jitter_stream = null; sourceDataLine = null; - if (System.getSecurityManager() == null) { - new Thread(runnable).start(); - } else { - new ManagedLocalsThread(runnable).start(); - } + new ManagedLocalsThread(runnable).start(); } return len; } diff --git a/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java b/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java index dd9ea860ec2..67b4ad852df 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java +++ b/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. * 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,7 +67,7 @@ class EventDispatchThread extends ManagedLocalsThread { private ArrayList eventFilters = new ArrayList(); EventDispatchThread(ThreadGroup group, String name, EventQueue queue) { - super(group, null, name); + super(group, name); setEventQueue(queue); } diff --git a/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java b/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java index 4bd6c8b7396..77d0b281b43 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java +++ b/jdk/src/java.desktop/share/classes/java/awt/image/renderable/RenderableImageProducer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * 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,12 +137,7 @@ public class RenderableImageProducer implements ImageProducer, Runnable { addConsumer(ic); // Need to build a runnable object for the Thread. String name = "RenderableImageProducer Thread"; - Thread thread; - if (System.getSecurityManager() == null) { - thread = new Thread(this, name); - } else { - thread = new ManagedLocalsThread(this); - } + Thread thread = new ManagedLocalsThread(this, name); thread.start(); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JTable.java b/jdk/src/java.desktop/share/classes/javax/swing/JTable.java index 3fa79bca434..3bcd70467f0 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JTable.java @@ -6402,12 +6402,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable }; // start printing on another thread - Thread th; - if (System.getSecurityManager() == null) { - th = new Thread(runnable); - } else { - th = new ManagedLocalsThread(runnable); - } + Thread th = new ManagedLocalsThread(runnable); th.start(); printingStatus.showModal(true); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java b/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java index c74ac7d0f6c..d221929b849 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/TimerQueue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * 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,8 +36,7 @@ import java.util.concurrent.*; import java.util.concurrent.locks.*; import java.util.concurrent.atomic.AtomicLong; import sun.awt.AppContext; -import sun.misc.InnocuousThread; - +import sun.misc.ManagedLocalsThread; /** * Internal class to manage all Timers using one thread. @@ -99,12 +98,8 @@ class TimerQueue implements Runnable final ThreadGroup threadGroup = AppContext.getAppContext().getThreadGroup(); AccessController.doPrivileged((PrivilegedAction) () -> { String name = "TimerQueue"; - Thread timerThread; - if (System.getSecurityManager() == null) { - timerThread = new Thread(threadGroup, TimerQueue.this, name); - } else { - timerThread = new InnocuousThread(threadGroup, TimerQueue.this, name); - } + Thread timerThread = new ManagedLocalsThread(threadGroup, + this, name); timerThread.setDaemon(true); timerThread.setPriority(Thread.NORM_PRIORITY); timerThread.start(); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java index b9841395f3b..d263907f742 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -271,11 +271,7 @@ public class BasicDirectoryModel extends AbstractListModel implements Pr this.currentDirectory = currentDirectory; this.fid = fid; String name = "Basic L&F File Loading Thread"; - if (System.getSecurityManager() == null) { - this.loadThread = new Thread(this, name); - } else { - this.loadThread = new ManagedLocalsThread(this, name); - } + this.loadThread = new ManagedLocalsThread(this, name); this.loadThread.start(); } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java index f6ac1e60ad1..a088bb6f082 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java @@ -2365,11 +2365,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A runnablePrinting.run(); } else { if (isEventDispatchThread) { - if (System.getSecurityManager() == null) { - new Thread(runnablePrinting).start(); - } else { - new ManagedLocalsThread(runnablePrinting).start(); - } + new ManagedLocalsThread(runnablePrinting).start(); printingStatus.showModal(true); } else { printingStatus.showModal(false); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java b/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java index 3a251030fe5..7109005c721 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/LayoutQueue.java @@ -92,12 +92,7 @@ public class LayoutQueue { } } while (work != null); }; - String name = "text-layout"; - if (System.getSecurityManager() == null) { - worker = new Thread(workerRunnable, name); - } else { - worker = new ManagedLocalsThread(workerRunnable, name); - } + worker = new ManagedLocalsThread(workerRunnable, "text-layout"); worker.setPriority(Thread.MIN_PRIORITY); worker.start(); } diff --git a/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java b/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java index 721c2a07473..d83cfbd3d26 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -862,7 +862,7 @@ class AppContextCreator extends ManagedLocalsThread { volatile boolean created = false; AppContextCreator(ThreadGroup group) { - super(group, null, "AppContextCreator"); + super(group, "AppContextCreator"); } public void run() { diff --git a/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java b/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java index fdfd17429d8..95a1fb9ddb3 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/AWTAutoShutdown.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.util.Map; import java.util.Set; import sun.awt.util.ThreadGroupUtils; -import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; /** @@ -336,14 +336,9 @@ public final class AWTAutoShutdown implements Runnable { */ private void activateBlockerThread() { AccessController.doPrivileged((PrivilegedAction) () -> { - Thread thread; String name = "AWT-Shutdown"; - if (System.getSecurityManager() == null) { - thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), this, - name); - } else { - thread = new InnocuousThread(this, name); - } + Thread thread = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), this, name); thread.setContextClassLoader(null); thread.setDaemon(false); blockerThread = thread; diff --git a/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java b/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java index 2125618d466..c6e0b02b834 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * 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,7 +44,7 @@ import java.beans.PropertyChangeSupport; import java.beans.PropertyChangeListener; import java.lang.ref.SoftReference; -import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; @@ -591,13 +591,9 @@ public final class AppContext { } public Thread run() { - Thread t; - if (System.getSecurityManager() == null) { - t = new Thread(appContext.getThreadGroup(), runnable); - } else { - t = new InnocuousThread(appContext.getThreadGroup(), runnable, "AppContext Disposer"); - } - t.setContextClassLoader(null); + Thread t = new ManagedLocalsThread(appContext.getThreadGroup(), + runnable, "AppContext Disposer"); + t.setContextClassLoader(appContext.getContextClassLoader()); t.setPriority(Thread.NORM_PRIORITY + 1); t.setDaemon(true); return t; diff --git a/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java b/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java index 3747257ad69..a5000b9836d 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/im/InputMethodManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,12 +167,7 @@ public abstract class InputMethodManager { // to choose from. Otherwise, just keep the instance. if (imm.hasMultipleInputMethods()) { imm.initialize(); - Thread immThread; - if (System.getSecurityManager() == null) { - immThread = new Thread(imm, threadName); - } else { - immThread = new ManagedLocalsThread(imm, threadName); - } + Thread immThread = new ManagedLocalsThread(imm, threadName); immThread.setDaemon(true); immThread.setPriority(Thread.NORM_PRIORITY + 1); immThread.start(); diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java b/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java index 9e71c9d47c2..4ad7eea1682 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. * 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 @@ class ImageFetcher extends ManagedLocalsThread { * Constructor for ImageFetcher -- only called by add() below. */ private ImageFetcher(ThreadGroup threadGroup, int index) { - super(threadGroup, null, "Image Fetcher " + index); + super(threadGroup, "Image Fetcher " + index); setDaemon(true); } diff --git a/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java b/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java index 439a30aa575..0ce75a7b235 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java +++ b/jdk/src/java.desktop/share/classes/sun/font/CreatedFontTracker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. * 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,7 +36,7 @@ import java.util.concurrent.TimeUnit; import sun.awt.AppContext; import sun.awt.util.ThreadGroupUtils; -import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; public class CreatedFontTracker { @@ -117,17 +117,13 @@ public class CreatedFontTracker { if (t == null) { // Add a shutdown hook to remove the temp file. AccessController.doPrivileged((PrivilegedAction) () -> { - if (System.getSecurityManager() == null) { - /* The thread must be a member of a thread group - * which will not get GCed before VM exit. - * Make its parent the top-level thread group. - */ - ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - t = new Thread(rootTG, TempFileDeletionHook::runHooks); - } else { - /* InnocuousThread is a member of a correct TG by default */ - t = new InnocuousThread(TempFileDeletionHook::runHooks); - } + /* The thread must be a member of a thread group + * which will not get GCed before VM exit. + * Make its parent the top-level thread group. + */ + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + t = new ManagedLocalsThread(rootTG, + TempFileDeletionHook::runHooks); /* Set context class loader to null in order to avoid * keeping a strong reference to an application classloader. */ diff --git a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java index 1c787d161e5..41e383df5bd 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java +++ b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. * 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,6 +55,7 @@ import sun.awt.SunToolkit; import sun.awt.util.ThreadGroupUtils; import sun.java2d.FontSupport; import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; /** @@ -2501,12 +2502,9 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { } }; AccessController.doPrivileged((PrivilegedAction) () -> { - if (System.getSecurityManager() == null) { - ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - fileCloser = new Thread(rootTG, fileCloserRunnable); - } else { - fileCloser = new InnocuousThread(fileCloserRunnable); - } + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + fileCloser = new ManagedLocalsThread(rootTG, + fileCloserRunnable); fileCloser.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(fileCloser); return null; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java b/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java index a3fd6143a77..0eee93fbac9 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/Disposer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ package sun.java2d; import sun.awt.util.ThreadGroupUtils; -import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; @@ -84,13 +84,8 @@ public class Disposer implements Runnable { disposerInstance = new Disposer(); AccessController.doPrivileged((PrivilegedAction) () -> { String name = "Java2D Disposer"; - Thread t; - if (System.getSecurityManager() == null) { - ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - t = new Thread(rootTG, disposerInstance, name); - } else { - t = new InnocuousThread(disposerInstance, name); - } + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + Thread t = new ManagedLocalsThread(rootTG, disposerInstance, name); t.setContextClassLoader(null); t.setDaemon(true); t.setPriority(Thread.MAX_PRIORITY); diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java b/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java index e7d2e2448f6..6db75f45f52 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ import java.io.FileNotFoundException; import java.security.AccessController; import java.security.PrivilegedAction; -import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; import sun.security.action.GetPropertyAction; /** @@ -420,12 +420,8 @@ public abstract class GraphicsPrimitive { public static void setShutdownHook() { AccessController.doPrivileged((PrivilegedAction) () -> { TraceReporter t = new TraceReporter(); - Thread thread; - if (System.getSecurityManager() == null) { - thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), t); - } else { - thread = new InnocuousThread(t); - } + Thread thread = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), t); thread.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(thread); return null; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java index 9e45eb3d7a1..e93bab4f568 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java @@ -29,6 +29,7 @@ import sun.awt.util.ThreadGroupUtils; import sun.java2d.pipe.RenderBuffer; import sun.java2d.pipe.RenderQueue; import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; import static sun.java2d.pipe.BufferedOpCodes.*; import java.security.AccessController; @@ -161,11 +162,7 @@ public class OGLRenderQueue extends RenderQueue { public QueueFlusher() { String name = "Java2D Queue Flusher"; - if (System.getSecurityManager() == null) { - this.thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), this, name); - } else { - this.thread = new InnocuousThread(this, name); - } + thread = new ManagedLocalsThread(ThreadGroupUtils.getRootThreadGroup(), this, name); thread.setDaemon(true); thread.setPriority(Thread.MAX_PRIORITY); thread.start(); diff --git a/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java b/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java index 0ae31dfb56e..cd3ded43f75 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java +++ b/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -987,12 +987,7 @@ public class PrintJob2D extends PrintJob implements Printable, Runnable { } private void startPrinterJobThread() { - String name = "printerJobThread"; - if (System.getSecurityManager() == null) { - printerJobThread = new Thread(this, name); - } else { - printerJobThread = new ManagedLocalsThread(this, name); - } + printerJobThread = new ManagedLocalsThread(this, "printerJobThread"); printerJobThread.start(); } diff --git a/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java b/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java index 5172acaa58b..573684a6048 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java +++ b/jdk/src/java.desktop/share/classes/sun/print/ServiceNotifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * 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,7 +50,7 @@ class ServiceNotifier extends ManagedLocalsThread { private PrintServiceAttributeSet lastSet; ServiceNotifier(PrintService service) { - super((Runnable) null, service.getName() + " notifier"); + super(service.getName() + " notifier"); this.service = service; listeners = new Vector<>(); try { diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java index 8c0dc54a3b8..db2f2dcfa5b 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,12 +116,7 @@ final class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer { showNativeDialog(); fd.setVisible(false); }; - if (System.getSecurityManager() == null) { - new Thread(task).start(); - } else { - new ManagedLocalsThread(task).start(); - } - + new ManagedLocalsThread(task).start(); } else { quit(); fd.setVisible(false); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java index 33cc44fccec..27661ee35d7 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * 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,7 +29,6 @@ import java.awt.*; import java.awt.event.*; import java.awt.peer.TrayIconPeer; import sun.awt.*; -import sun.misc.InnocuousThread; import sun.misc.ManagedLocalsThread; import java.awt.image.*; @@ -455,11 +454,7 @@ public abstract class InfoWindow extends Window { final Thread thread; Displayer() { - if (System.getSecurityManager() == null) { - this.thread = new Thread(this); - } else { - this.thread = new ManagedLocalsThread(this); - } + this.thread = new ManagedLocalsThread(this); this.thread.setDaemon(true); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index 3f95f42611a..1b890710594 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -281,12 +281,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable { } }; String name = "XToolkt-Shutdown-Thread"; - Thread shutdownThread; - if (System.getSecurityManager() == null) { - shutdownThread = new Thread(ThreadGroupUtils.getRootThreadGroup(), r, name); - } else { - shutdownThread = new InnocuousThread(r, name); - } + Thread shutdownThread = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), r, name); shutdownThread.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdownThread); return null; @@ -333,12 +329,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable { toolkitThread = AccessController.doPrivileged((PrivilegedAction) () -> { String name = "AWT-XAWT"; - Thread thread; - if (System.getSecurityManager() == null) { - thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), XToolkit.this, name); - } else { - thread = new InnocuousThread(XToolkit.this, name); - } + Thread thread = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), this, name); thread.setContextClassLoader(null); thread.setPriority(Thread.NORM_PRIORITY + 1); thread.setDaemon(true); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java index c6b9cc94044..f24df1fd216 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java @@ -43,7 +43,7 @@ import sun.java2d.xr.XRGraphicsConfig; import sun.java2d.loops.SurfaceType; import sun.awt.util.ThreadGroupUtils; -import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; /** * This is an implementation of a GraphicsDevice object for a single @@ -437,12 +437,8 @@ public final class X11GraphicsDevice extends GraphicsDevice } }; String name = "Display-Change-Shutdown-Thread-" + screen; - Thread t; - if (System.getSecurityManager() == null) { - t = new Thread(ThreadGroupUtils.getRootThreadGroup(), r, name); - } else { - t = new InnocuousThread(r, name); - } + Thread t = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), r, name); t.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(t); return null; diff --git a/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java b/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java index e40ba274b46..7cf6bf0aced 100644 --- a/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java +++ b/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -213,12 +213,7 @@ public class PrintServiceLookupProvider extends PrintServiceLookup public PrintServiceLookupProvider() { // start the printer listener thread if (pollServices) { - Thread thr; - if (System.getSecurityManager() == null) { - thr = new Thread(new PrinterChangeListener()); - } else { - thr = new ManagedLocalsThread(new PrinterChangeListener()); - } + Thread thr = new ManagedLocalsThread(new PrinterChangeListener()); thr.setDaemon(true); thr.start(); IPPPrintService.debug_println(debugPrefix+"polling turned on"); diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index 4817e2a62bc..e87379a58f0 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -41,8 +41,7 @@ import java.util.stream.Stream; import static sun.awt.shell.Win32ShellFolder2.*; import sun.awt.OSInfo; import sun.awt.util.ThreadGroupUtils; -import sun.misc.InnocuousThread; - +import sun.misc.ManagedLocalsThread; // NOTE: This class supersedes Win32ShellFolderManager, which was removed // from distribution after version 1.4.2. @@ -525,12 +524,8 @@ final class Win32ShellFolderManager2 extends ShellFolderManager { return null; }); AccessController.doPrivileged((PrivilegedAction) () -> { - Thread t; - if (System.getSecurityManager() == null) { - t = new Thread(ThreadGroupUtils.getRootThreadGroup(), shutdownHook); - } else { - t = new InnocuousThread(shutdownHook); - } + Thread t = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), shutdownHook); Runtime.getRuntime().addShutdownHook(t); return null; }); @@ -549,17 +544,12 @@ final class Win32ShellFolderManager2 extends ShellFolderManager { }; comThread = AccessController.doPrivileged((PrivilegedAction) () -> { String name = "Swing-Shell"; - Thread thread; - if (System.getSecurityManager() == null) { - /* The thread must be a member of a thread group - * which will not get GCed before VM exit. - * Make its parent the top-level thread group. - */ - thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), comRun, name); - } else { - /* InnocuousThread is a member of a correct TG by default */ - thread = new InnocuousThread(comRun, name); - } + /* The thread must be a member of a thread group + * which will not get GCed before VM exit. + * Make its parent the top-level thread group. + */ + Thread thread = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), comRun, name); thread.setDaemon(true); return thread; }); diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java index 4050668c65a..e75f3b9f486 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,11 +98,7 @@ final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer { @Override public void show() { - if (System.getSecurityManager() == null) { - new Thread(this::_show).start(); - } else { - new ManagedLocalsThread(this::_show).start(); - } + new ManagedLocalsThread(this::_show).start(); } @Override diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java index 7a146d965cd..10d99948b10 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,10 +53,6 @@ final class WPageDialogPeer extends WPrintDialogPeer { } ((WPrintDialog)target).setVisible(false); }; - if (System.getSecurityManager() == null) { - new Thread(runnable).start(); - } else { - new ManagedLocalsThread(runnable).start(); - } + new ManagedLocalsThread(runnable).start(); } } diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java index de4abab4fa3..99c727493d1 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,11 +78,7 @@ class WPrintDialogPeer extends WWindowPeer implements DialogPeer { } ((WPrintDialog)target).setVisible(false); }; - if (System.getSecurityManager() == null) { - new Thread(runnable).start(); - } else { - new ManagedLocalsThread(runnable).start(); - } + new ManagedLocalsThread(runnable).start(); } synchronized void setHWnd(long hwnd) { diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java index 02d8f49aba1..e4e6675acde 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java @@ -51,7 +51,7 @@ import sun.awt.datatransfer.DataTransferer; import sun.java2d.d3d.D3DRenderQueue; import sun.java2d.opengl.OGLRenderQueue; -import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; import sun.print.PrintJob2D; import java.awt.dnd.DragSource; @@ -255,12 +255,7 @@ public final class WToolkit extends SunToolkit implements Runnable { (PrivilegedAction) ThreadGroupUtils::getRootThreadGroup); if (!startToolkitThread(this, rootTG)) { String name = "AWT-Windows"; - Thread toolkitThread; - if (System.getSecurityManager() == null) { - toolkitThread = new Thread(rootTG, this, name); - } else { - toolkitThread = new InnocuousThread(this, name); - } + Thread toolkitThread = new ManagedLocalsThread(rootTG, this, name); toolkitThread.setDaemon(true); toolkitThread.start(); } @@ -287,16 +282,12 @@ public final class WToolkit extends SunToolkit implements Runnable { private void registerShutdownHook() { AccessController.doPrivileged((PrivilegedAction) () -> { - Thread shutdown; - if (System.getSecurityManager() == null) { - shutdown = new Thread(ThreadGroupUtils.getRootThreadGroup(), this::shutdown); - } else { - shutdown = new InnocuousThread(this::shutdown); - } + Thread shutdown = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), this::shutdown); shutdown.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdown); return null; - }); + }); } @Override diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java index e4ebb4b9cd8..60bdc361d6c 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java @@ -49,7 +49,7 @@ import sun.java2d.SurfaceData; import sun.java2d.windows.GDIWindowSurfaceData; import sun.java2d.d3d.D3DSurfaceData.D3DWindowSurfaceData; import sun.java2d.windows.WindowsFlags; -import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; /** * This class handles rendering to the screen with the D3D pipeline. @@ -99,12 +99,8 @@ public class D3DScreenUpdateManager extends ScreenUpdateManager done = true; wakeUpUpdateThread(); }; - Thread shutdown; - if (System.getSecurityManager() == null) { - shutdown = new Thread(ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); - } else { - shutdown = new InnocuousThread(shutdownRunnable); - } + Thread shutdown = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); shutdown.setContextClassLoader(null); try { Runtime.getRuntime().addShutdownHook(shutdown); @@ -351,15 +347,9 @@ public class D3DScreenUpdateManager extends ScreenUpdateManager private synchronized void startUpdateThread() { if (screenUpdater == null) { screenUpdater = AccessController.doPrivileged((PrivilegedAction) () -> { - Thread t; String name = "D3D Screen Updater"; - if (System.getSecurityManager() == null) { - t = new Thread(ThreadGroupUtils.getRootThreadGroup(), - D3DScreenUpdateManager.this, - name); - } else { - t = new InnocuousThread(D3DScreenUpdateManager.this, name); - } + Thread t = new ManagedLocalsThread( + ThreadGroupUtils.getRootThreadGroup(), this, name); // REMIND: should it be higher? t.setPriority(Thread.NORM_PRIORITY + 2); t.setDaemon(true); diff --git a/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java b/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java index 903673efdbf..e9139b46525 100644 --- a/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java +++ b/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,12 +99,7 @@ public class PrintServiceLookupProvider extends PrintServiceLookup { return; } // start the printer listener thread - Thread thr; - if (System.getSecurityManager() == null) { - thr = new Thread(new PrinterChangeListener()); - } else { - thr = new ManagedLocalsThread(new PrinterChangeListener()); - } + Thread thr = new ManagedLocalsThread(new PrinterChangeListener()); thr.setDaemon(true); thr.start(); } /* else condition ought to never happen! */ diff --git a/jdk/test/java/awt/EventDispatchThread/PropertyPermissionOnEDT/PropertyPermissionOnEDT.java b/jdk/test/java/awt/EventDispatchThread/PropertyPermissionOnEDT/PropertyPermissionOnEDT.java new file mode 100644 index 00000000000..ef0e009ac5e --- /dev/null +++ b/jdk/test/java/awt/EventDispatchThread/PropertyPermissionOnEDT/PropertyPermissionOnEDT.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/** + * @test + * @bug 8080405 + * @run main/othervm/policy=java.policy -Djava.security.manager PropertyPermissionOnEDT + */ +public final class PropertyPermissionOnEDT { + + public static void main(final String[] args) throws Exception { + SwingUtilities.invokeAndWait(PropertyPermissionOnEDT::test); + + JFrame frame = new JFrame(); + frame.addMouseListener(new MouseListener() { + @Override + public void mouseClicked(final MouseEvent e) { + test(); + } + + @Override + public void mousePressed(MouseEvent e) { + test(); + } + + @Override + public void mouseReleased(MouseEvent e) { + test(); + } + + @Override + public void mouseEntered(MouseEvent e) { + test(); + } + + @Override + public void mouseExited(MouseEvent e) { + test(); + } + }); + frame.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + test(); + } + + @Override + public void focusLost(FocusEvent e) { + test(); + } + }); + frame.addMouseWheelListener(e -> test()); + frame.addWindowStateListener(e -> test()); + + frame.setSize(100, 100); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + Robot robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(100); + Point loc = frame.getLocationOnScreen(); + robot.mouseMove(loc.x + frame.getWidth() / 2, + loc.y + frame.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mouseWheel(100); + frame.dispose(); + } + + private static void test() { + String property = System.getProperty("os.name"); + System.out.println("property = " + property); + } +} diff --git a/jdk/test/java/awt/EventDispatchThread/PropertyPermissionOnEDT/java.policy b/jdk/test/java/awt/EventDispatchThread/PropertyPermissionOnEDT/java.policy new file mode 100644 index 00000000000..461664148ba --- /dev/null +++ b/jdk/test/java/awt/EventDispatchThread/PropertyPermissionOnEDT/java.policy @@ -0,0 +1,4 @@ +grant { + permission java.util.PropertyPermission "os.name", "read"; + permission java.awt.AWTPermission "createRobot"; +}; From dd57d9f3b9a333be68c6247732f3234cfe2d4f86 Mon Sep 17 00:00:00 2001 From: Anton Nashatyrev Date: Mon, 29 Jun 2015 13:47:28 +0300 Subject: [PATCH 10/21] 8080504: [macosx] SunToolkit.realSync() may hang Reviewed-by: serb, prr --- .../macosx/native/libawt_lwawt/awt/LWCToolkit.m | 2 +- .../macosx/native/libosxapp/NSApplicationAWT.h | 2 +- .../macosx/native/libosxapp/NSApplicationAWT.m | 10 ++++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m index 07cd78b38c3..f84a3d3f996 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m @@ -376,7 +376,7 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_nativeSyncQueue if ([sharedApp isKindOfClass:[NSApplicationAWT class]]) { NSApplicationAWT* theApp = (NSApplicationAWT*)sharedApp; [theApp postDummyEvent]; - [theApp waitForDummyEvent]; + [theApp waitForDummyEvent:timeout]; } else { // could happen if we are embedded inside SWT application, // in this case just spin a single empty block through diff --git a/jdk/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.h b/jdk/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.h index 99c7d63175a..1025cd7c533 100644 --- a/jdk/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.h +++ b/jdk/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.h @@ -38,7 +38,7 @@ - (void) setDockIconWithEnv:(JNIEnv *)env; - (void) postDummyEvent; - (void) postRunnableEvent:(void (^)())block; -- (void) waitForDummyEvent; +- (void) waitForDummyEvent:(long long) timeout; + (void) runAWTLoopWithApp:(NSApplication*)app; diff --git a/jdk/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m b/jdk/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m index fdaa1c3a8cb..906477fa8a7 100644 --- a/jdk/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m +++ b/jdk/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m @@ -398,8 +398,14 @@ AWT_ASSERT_APPKIT_THREAD; [pool drain]; } -- (void)waitForDummyEvent { - [seenDummyEventLock lockWhenCondition:YES]; +- (void)waitForDummyEvent:(long long) timeout { + if (timeout >= 0) { + double sec = ((double) timeout)/1000; + [seenDummyEventLock lockWhenCondition:YES + beforeDate:[NSDate dateWithTimeIntervalSinceNow:sec]]; + } else { + [seenDummyEventLock lockWhenCondition:YES]; + } [seenDummyEventLock unlock]; [seenDummyEventLock release]; From e482146d84770b204a015c66a714c013f0b64004 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 30 Jun 2015 10:45:32 +0300 Subject: [PATCH 11/21] 8098535: Test closed/java/awt/Clipboard/ImageTransferTest/ImageTransferTest fails on OEL 7.1 Reviewed-by: serb, azvegint --- .../java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c index 1aaa1eddc63..2e96cc843c6 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -554,8 +554,10 @@ static void update_poll_timeout(int timeout_control) { curPollTimeout = min(AWT_MAX_POLL_TIMEOUT, curPollTimeout); } else if (timeout_control == TIMEOUT_EVENTS) { /* subtract 1/4 (plus 1, in case the division truncates to 0) */ - curPollTimeout -= ((curPollTimeout>>2) + 1); - curPollTimeout = max(AWT_MIN_POLL_TIMEOUT, curPollTimeout); + if (curPollTimeout > 0) { + curPollTimeout -= ((curPollTimeout>>2) + 1); + curPollTimeout = max(AWT_MIN_POLL_TIMEOUT, curPollTimeout); + } } break; case AWT_POLL_AGING_FAST: From 0ccb98b72a03466712284c2938f75eb61bbbe4ed Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 30 Jun 2015 11:04:58 +0300 Subject: [PATCH 12/21] 8085895: The Textfield can't be shown after clicking "Show Textfield" button Reviewed-by: serb, azvegint --- .../unix/classes/sun/awt/X11/XTextAreaPeer.java | 4 ++-- .../unix/classes/sun/awt/X11/XTextFieldPeer.java | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextAreaPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextAreaPeer.java index 575d7c02387..428d1d27d55 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextAreaPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextAreaPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,6 +138,7 @@ final class XTextAreaPeer extends XComponentPeer implements TextAreaPeer { setScrollBarVisibility(); // After this line we should not change the component's text firstChangeSkipped = true; + compAccessor.setPeer(textPane, this); } @Override @@ -146,7 +147,6 @@ final class XTextAreaPeer extends XComponentPeer implements TextAreaPeer { // visible caret has a timer thread which must be stopped jtext.getCaret().setVisible(false); jtext.removeNotify(); - textPane.removeNotify(); super.dispose(); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextFieldPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextFieldPeer.java index 6841d1546a1..b936b6bb26a 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextFieldPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTextFieldPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * 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 @@ final class XTextFieldPeer extends XComponentPeer implements TextFieldPeer { // After this line we should not change the component's text firstChangeSkipped = true; + AWTAccessor.getComponentAccessor().setPeer(xtext, this); } @Override @@ -102,7 +103,6 @@ final class XTextFieldPeer extends XComponentPeer implements TextFieldPeer { XToolkit.specialPeerMap.remove(xtext); // visible caret has a timer thread which must be stopped xtext.getCaret().setVisible(false); - xtext.removeNotify(); super.dispose(); } @@ -259,7 +259,9 @@ final class XTextFieldPeer extends XComponentPeer implements TextFieldPeer { } background = c; if (xtext != null) { - xtext.setBackground(c); + if (xtext.getBackground() != c) { + xtext.setBackground(c); + } xtext.setSelectedTextColor(c); } repaintText(); @@ -269,7 +271,9 @@ final class XTextFieldPeer extends XComponentPeer implements TextFieldPeer { public void setForeground(Color c) { foreground = c; if (xtext != null) { - xtext.setForeground(foreground); + if (xtext.getForeground() != c) { + xtext.setForeground(foreground); + } xtext.setSelectionColor(foreground); xtext.setCaretColor(foreground); } @@ -280,7 +284,7 @@ final class XTextFieldPeer extends XComponentPeer implements TextFieldPeer { public void setFont(Font f) { synchronized (getStateLock()) { font = f; - if (xtext != null) { + if (xtext != null && xtext.getFont() != f) { xtext.setFont(font); } } From 11e135e30e3034cc4a861f2f0f1ad5b1fe894ba1 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 30 Jun 2015 18:26:38 +0300 Subject: [PATCH 13/21] 8129830: JTree drag/drop on lower half of last child of container incorrect Reviewed-by: alexsch, azvegint --- .../share/classes/javax/swing/JTree.java | 7 + .../javax/swing/plaf/basic/BasicTreeUI.java | 14 +- .../JTree/DnD/LastNodeLowerHalfDrop.java | 384 ++++++++++++++++++ 3 files changed, 402 insertions(+), 3 deletions(-) create mode 100644 jdk/test/javax/swing/JTree/DnD/LastNodeLowerHalfDrop.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JTree.java b/jdk/src/java.desktop/share/classes/javax/swing/JTree.java index ff3a5ef389f..4cec5c377d7 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JTree.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JTree.java @@ -1365,6 +1365,13 @@ public class JTree extends JComponent implements Scrollable, Accessible child = getPathForRow(index); parent = child.getParentPath(); + TreePath prev = getPathForRow(row).getParentPath(); + if (prev != null && !prev.equals(parent)) { + location = new DropLocation(p, prev, + model.getChildCount(prev.getLastPathComponent())); + break; + } + } else { assert checkOn; location = new DropLocation(p, getPathForRow(row), -1); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java index d01db84f37f..14e46845031 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1497,8 +1497,16 @@ public class BasicTreeUI extends TreeUI rect.x = xRect.x; rect.width = xRect.width; } else { - rect = tree.getPathBounds(path.pathByAddingChild( - model.getChild(path.getLastPathComponent(), index))); + if (index >= model.getChildCount(path.getLastPathComponent())) { + rect = tree.getPathBounds(path.pathByAddingChild( + model.getChild(path.getLastPathComponent(), + index - 1))); + rect.y = rect.y + rect.height; + } else { + rect = tree.getPathBounds(path.pathByAddingChild( + model.getChild(path.getLastPathComponent(), + index))); + } } } diff --git a/jdk/test/javax/swing/JTree/DnD/LastNodeLowerHalfDrop.java b/jdk/test/javax/swing/JTree/DnD/LastNodeLowerHalfDrop.java new file mode 100644 index 00000000000..e76a16eb1e4 --- /dev/null +++ b/jdk/test/javax/swing/JTree/DnD/LastNodeLowerHalfDrop.java @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 8129830 + @summary JTree drag/drop on lower half of last child of container incorrect + @author Semyon Sadetsky + */ + +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.event.InputEvent; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; + +public class LastNodeLowerHalfDrop { + + private static DefaultMutableTreeNode b1; + private static DefaultMutableTreeNode b2; + private static DefaultMutableTreeNode c; + private static JTree jTree; + private static DefaultMutableTreeNode a; + private static DefaultMutableTreeNode b; + private static DefaultMutableTreeNode a1; + private static Point dragPoint; + private static Point dropPoint; + private static JFrame f; + private static DefaultMutableTreeNode c1; + private static DefaultMutableTreeNode root; + + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + f = new JFrame(); + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + f.add(new LastNodeLowerHalfDrop().getContent()); + f.setSize(400, 400); + f.setLocationRelativeTo(null); + f.setVisible(true); + } + }); + testCase(b2, a1, +0.4f); + if (!"b2".equals(jTree.getModel(). + getChild(a, a.getChildCount() - 1).toString())) { + throw new RuntimeException("b1 was not inserted in the last position in a"); + } + testCase(c1, c, -0.4f); + if (!"c1".equals(jTree.getModel().getChild(root, 2).toString())) { + throw new RuntimeException("c1 was not inserted beetween c and b nodes"); + } + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + f.dispose(); + } + }); + System.out.printf("ok"); + } + + static void testCase(DefaultMutableTreeNode drag, + DefaultMutableTreeNode drop, float shift) throws Exception { + Robot robot = new Robot(); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + Rectangle rectDrag = + jTree.getPathBounds(new TreePath(drag.getPath())); + dragPoint = new Point((int)rectDrag.getCenterX(), + (int) rectDrag.getCenterY()); + SwingUtilities.convertPointToScreen(dragPoint, jTree); + Rectangle rectDrop = + jTree.getPathBounds(new TreePath(drop.getPath())); + dropPoint = new Point(rectDrop.x + 5, + (int) (rectDrop.getCenterY() + shift * rectDrop.height)); + SwingUtilities.convertPointToScreen(dropPoint, jTree); + } + }); + + robot.mouseMove(dragPoint.x, dragPoint.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.delay(400); + robot.mouseMove(dropPoint.x, dropPoint.y); + robot.delay(400); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + + robot.waitForIdle(); + } + + private JScrollPane getContent() { + jTree = new JTree(getTreeModel()); + jTree.setRootVisible(false); + jTree.setDragEnabled(true); + jTree.setDropMode(DropMode.INSERT); + jTree.setTransferHandler(new TreeTransferHandler()); + jTree.getSelectionModel().setSelectionMode( + TreeSelectionModel.SINGLE_TREE_SELECTION); + expandTree(jTree); + return new JScrollPane(jTree); + } + + protected static TreeModel getTreeModel() { + root = new DefaultMutableTreeNode("Root"); + + a = new DefaultMutableTreeNode("A"); + root.add(a); + a1 = new DefaultMutableTreeNode("a1"); + a.add(a1); + + b = new DefaultMutableTreeNode("B"); + root.add(b); + b1 = new DefaultMutableTreeNode("b1"); + b.add(b1); + b2 = new DefaultMutableTreeNode("b2"); + b.add(b2); + + c = new DefaultMutableTreeNode("C"); + root.add(c); + c1 = new DefaultMutableTreeNode("c1"); + c.add(c1); + return new DefaultTreeModel(root); + } + + private void expandTree(JTree tree) { + DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel() + .getRoot(); + Enumeration e = root.breadthFirstEnumeration(); + while (e.hasMoreElements()) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.nextElement(); + if (node.isLeaf()) { + continue; + } + int row = tree.getRowForPath(new TreePath(node.getPath())); + tree.expandRow(row); + } + } +} + +class TreeTransferHandler extends TransferHandler { + DataFlavor nodesFlavor; + DataFlavor[] flavors = new DataFlavor[1]; + DefaultMutableTreeNode[] nodesToRemove; + + public TreeTransferHandler() { + try { + String mimeType = DataFlavor.javaJVMLocalObjectMimeType + + ";class=\"" + + javax.swing.tree.DefaultMutableTreeNode[].class.getName() + + "\""; + nodesFlavor = new DataFlavor(mimeType); + flavors[0] = nodesFlavor; + } catch (ClassNotFoundException e) { + System.out.println("ClassNotFound: " + e.getMessage()); + } + } + + @Override + public boolean canImport(TransferHandler.TransferSupport support) { + if (!support.isDrop()) { + return false; + } + support.setShowDropLocation(true); + if (!support.isDataFlavorSupported(nodesFlavor)) { + return false; + } + // Do not allow a drop on the drag source selections. + JTree.DropLocation dl = (JTree.DropLocation) support.getDropLocation(); + JTree tree = (JTree) support.getComponent(); + int dropRow = tree.getRowForPath(dl.getPath()); + int[] selRows = tree.getSelectionRows(); + for (int i = 0; i < selRows.length; i++) { + if (selRows[i] == dropRow) { + return false; + } + } + // Do not allow MOVE-action drops if a non-leaf node is + // selected unless all of its children are also selected. + int action = support.getDropAction(); + if (action == MOVE) { + return haveCompleteNode(tree); + } + // Do not allow a non-leaf node to be copied to a level + // which is less than its source level. + TreePath dest = dl.getPath(); + DefaultMutableTreeNode target = (DefaultMutableTreeNode) + dest.getLastPathComponent(); + TreePath path = tree.getPathForRow(selRows[0]); + DefaultMutableTreeNode firstNode = (DefaultMutableTreeNode) + path.getLastPathComponent(); + if (firstNode.getChildCount() > 0 + && target.getLevel() < firstNode.getLevel()) { + return false; + } + return true; + } + + private boolean haveCompleteNode(JTree tree) { + int[] selRows = tree.getSelectionRows(); + TreePath path = tree.getPathForRow(selRows[0]); + DefaultMutableTreeNode first = (DefaultMutableTreeNode) + path.getLastPathComponent(); + int childCount = first.getChildCount(); + // first has children and no children are selected. + if (childCount > 0 && selRows.length == 1) { + return false; + } + // first may have children. + for (int i = 1; i < selRows.length; i++) { + path = tree.getPathForRow(selRows[i]); + DefaultMutableTreeNode next = (DefaultMutableTreeNode) + path.getLastPathComponent(); + if (first.isNodeChild(next)) { + // Found a child of first. + if (childCount > selRows.length - 1) { + // Not all children of first are selected. + return false; + } + } + } + return true; + } + + @Override + protected Transferable createTransferable(JComponent c) { + JTree tree = (JTree) c; + TreePath[] paths = tree.getSelectionPaths(); + if (paths != null) { + // Make up a node array of copies for transfer and + // another for/of the nodes that will be removed in + // exportDone after a successful drop. + List copies = new ArrayList<>(); + List toRemove = new ArrayList<>(); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) + paths[0].getLastPathComponent(); + DefaultMutableTreeNode copy = copy(node); + copies.add(copy); + toRemove.add(node); + for (int i = 1; i < paths.length; i++) { + DefaultMutableTreeNode next = (DefaultMutableTreeNode) paths[i] + .getLastPathComponent(); + // Do not allow higher level nodes to be added to list. + if (next.getLevel() < node.getLevel()) { + break; + } else if (next.getLevel() > node.getLevel()) { // child node + copy.add(copy(next)); + // node already contains child + } else { // sibling + copies.add(copy(next)); + toRemove.add(next); + } + } + DefaultMutableTreeNode[] nodes = copies + .toArray(new DefaultMutableTreeNode[copies.size()]); + nodesToRemove = toRemove.toArray( + new DefaultMutableTreeNode[toRemove.size()]); + return new NodesTransferable(nodes); + } + return null; + } + + /** + * Defensive copy used in createTransferable. + */ + private DefaultMutableTreeNode copy(TreeNode node) { + return new DefaultMutableTreeNode(node); + } + + @Override + protected void exportDone(JComponent source, Transferable data, int action) { + if ((action & MOVE) == MOVE) { + JTree tree = (JTree) source; + DefaultTreeModel model = (DefaultTreeModel) tree.getModel(); + // Remove nodes saved in nodesToRemove in createTransferable. + for (DefaultMutableTreeNode nodesToRemove1 : nodesToRemove) { + model.removeNodeFromParent(nodesToRemove1); + } + } + } + + @Override + public int getSourceActions(JComponent c) { + return COPY_OR_MOVE; + } + + @Override + public boolean importData(TransferHandler.TransferSupport support) { + if (!canImport(support)) { + return false; + } + // Extract transfer data. + DefaultMutableTreeNode[] nodes = null; + try { + Transferable t = support.getTransferable(); + nodes = (DefaultMutableTreeNode[]) t.getTransferData(nodesFlavor); + } catch (UnsupportedFlavorException ufe) { + System.out.println("UnsupportedFlavor: " + ufe.getMessage()); + } catch (java.io.IOException ioe) { + System.out.println("I/O error: " + ioe.getMessage()); + } + // Get drop location info. + JTree.DropLocation dl = (JTree.DropLocation) support.getDropLocation(); + int childIndex = dl.getChildIndex(); + TreePath dest = dl.getPath(); + DefaultMutableTreeNode parent = (DefaultMutableTreeNode) + dest.getLastPathComponent(); + JTree tree = (JTree) support.getComponent(); + DefaultTreeModel model = (DefaultTreeModel) tree.getModel(); + // Configure for drop mode. + int index = childIndex; // DropMode.INSERT + if (childIndex == -1) { // DropMode.ON + index = parent.getChildCount(); + } + // Add data to model. + for (DefaultMutableTreeNode node : nodes) { + model.insertNodeInto(node, parent, index++); + } + return true; + } + + @Override + public String toString() { + return getClass().getName(); + } + + public class NodesTransferable implements Transferable { + DefaultMutableTreeNode[] nodes; + + public NodesTransferable(DefaultMutableTreeNode[] nodes) { + this.nodes = nodes; + } + + @Override + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException { + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + return nodes; + } + + @Override + public DataFlavor[] getTransferDataFlavors() { + return flavors; + } + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + return nodesFlavor.equals(flavor); + } + } +} \ No newline at end of file From 5941f4ad529d0303fc7d14f45be5176a6a1500bb Mon Sep 17 00:00:00 2001 From: Peter Levart Date: Thu, 2 Jul 2015 08:17:25 +0200 Subject: [PATCH 14/21] 8080695: splashscreen_png.c compile error with gcc 4.9.2 Mark locals volatile to silence gcc arround longjmp Reviewed-by: azvegint, serb --- .../share/native/libsplashscreen/splashscreen_png.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_png.c b/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_png.c index aeddf868082..3f77ea6d6d0 100644 --- a/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_png.c +++ b/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_png.c @@ -48,8 +48,8 @@ SplashDecodePng(Splash * splash, png_rw_ptr read_func, void *io_ptr) int stride; ImageFormat srcFormat; png_uint_32 i, rowbytes; - png_bytepp row_pointers = NULL; - png_bytep image_data = NULL; + volatile png_bytepp row_pointers = NULL; + volatile png_bytep image_data = NULL; int success = 0; double gamma; From 94d36649af402367ed86742b5456dddeddd5aac3 Mon Sep 17 00:00:00 2001 From: Zoltan Majo Date: Fri, 3 Jul 2015 07:23:45 +0200 Subject: [PATCH 15/21] 8076112: Add @HotSpotIntrinsicCandidate annotation to indicate methods for which Java Runtime has intrinsics Annotate possibly intrinsified methods with @HotSpotIntrinsicCandidate. Add checks omitted by intrinsics to the library code. Add CheckIntrinsics flags to check consistency of intrinsics. Reviewed-by: jrose, kvn, thartmann, vlivanov, abuckley, darcy, ascarpino, briangoetz, alanb, aph, dnsimon --- jdk/make/mapfiles/libzip/mapfile-vers | 4 +- .../com/sun/crypto/provider/AESCrypt.java | 45 ++++++- .../crypto/provider/CipherBlockChaining.java | 57 ++++++-- .../com/sun/crypto/provider/GHASH.java | 3 + .../share/classes/java/lang/Boolean.java | 4 + .../share/classes/java/lang/Byte.java | 4 + .../share/classes/java/lang/Character.java | 5 + .../share/classes/java/lang/Class.java | 9 ++ .../share/classes/java/lang/Double.java | 6 + .../share/classes/java/lang/Float.java | 6 + .../share/classes/java/lang/Integer.java | 8 ++ .../share/classes/java/lang/Long.java | 7 + .../share/classes/java/lang/Math.java | 27 +++- .../share/classes/java/lang/Object.java | 6 + .../share/classes/java/lang/Short.java | 5 + .../share/classes/java/lang/StrictMath.java | 7 +- .../share/classes/java/lang/String.java | 5 + .../share/classes/java/lang/StringBuffer.java | 8 ++ .../classes/java/lang/StringBuilder.java | 8 ++ .../share/classes/java/lang/System.java | 5 + .../share/classes/java/lang/Thread.java | 4 +- .../java/lang/invoke/MethodHandle.java | 8 ++ .../java/lang/invoke/MethodHandleImpl.java | 3 + .../classes/java/lang/ref/Reference.java | 2 + .../classes/java/lang/reflect/Array.java | 4 + .../classes/java/lang/reflect/Method.java | 2 + .../share/classes/java/math/BigInteger.java | 26 ++++ .../share/classes/java/nio/Buffer.java | 2 + .../share/classes/java/util/Arrays.java | 4 + .../classes/java/util/stream/Streams.java | 2 + .../share/classes/java/util/zip/CRC32.java | 49 ++++++- .../share/classes/java/util/zip/CRC32C.java | 4 + .../internal/HotSpotIntrinsicCandidate.java | 125 ++++++++++++++++++ .../share/classes/sun/misc/Unsafe.java | 82 ++++++++++++ .../share/classes/sun/nio/cs/ISO_8859_1.java | 42 +++++- .../share/classes/sun/reflect/Reflection.java | 3 + .../sun/security/provider/DigestBase.java | 27 ++++ .../classes/sun/security/provider/SHA.java | 24 +++- .../classes/sun/security/provider/SHA2.java | 24 +++- .../classes/sun/security/provider/SHA5.java | 23 +++- jdk/src/java.base/share/native/libzip/CRC32.c | 8 +- 41 files changed, 667 insertions(+), 30 deletions(-) create mode 100644 jdk/src/java.base/share/classes/jdk/internal/HotSpotIntrinsicCandidate.java diff --git a/jdk/make/mapfiles/libzip/mapfile-vers b/jdk/make/mapfiles/libzip/mapfile-vers index ad1682ff88f..ceace23f26d 100644 --- a/jdk/make/mapfiles/libzip/mapfile-vers +++ b/jdk/make/mapfiles/libzip/mapfile-vers @@ -32,8 +32,8 @@ SUNWprivate_1.1 { Java_java_util_zip_Adler32_updateBytes; Java_java_util_zip_Adler32_updateByteBuffer; Java_java_util_zip_CRC32_update; - Java_java_util_zip_CRC32_updateBytes; - Java_java_util_zip_CRC32_updateByteBuffer; + Java_java_util_zip_CRC32_updateBytes0; + Java_java_util_zip_CRC32_updateByteBuffer0; Java_java_util_zip_Deflater_deflateBytes; Java_java_util_zip_Deflater_end; Java_java_util_zip_Deflater_getAdler; diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java index 02cc426e34b..b6b1d34c450 100644 --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/AESCrypt.java @@ -38,6 +38,9 @@ package com.sun.crypto.provider; import java.security.InvalidKeyException; import java.util.Arrays; +import java.util.Objects; + +import jdk.internal.HotSpotIntrinsicCandidate; /** * Rijndael --pronounced Reindaal-- is a symmetric cipher with a 128-bit @@ -346,7 +349,16 @@ final class AESCrypt extends SymmetricCipher implements AESConstants * Encrypt exactly one block of plaintext. */ void encryptBlock(byte[] in, int inOffset, - byte[] out, int outOffset) + byte[] out, int outOffset) { + cryptBlockCheck(in, inOffset); + cryptBlockCheck(out, outOffset); + implEncryptBlock(in, inOffset, out, outOffset); + } + + // Encryption operation. Possibly replaced with a compiler intrinsic. + @HotSpotIntrinsicCandidate + private void implEncryptBlock(byte[] in, int inOffset, + byte[] out, int outOffset) { int keyOffset = 0; int t0 = ((in[inOffset++] ) << 24 | @@ -412,12 +424,20 @@ final class AESCrypt extends SymmetricCipher implements AESConstants out[outOffset ] = (byte)(S[(t2 ) & 0xFF] ^ (tt )); } - /** * Decrypt exactly one block of plaintext. */ void decryptBlock(byte[] in, int inOffset, - byte[] out, int outOffset) + byte[] out, int outOffset) { + cryptBlockCheck(in, inOffset); + cryptBlockCheck(out, outOffset); + implDecryptBlock(in, inOffset, out, outOffset); + } + + // Decrypt operation. Possibly replaced with a compiler intrinsic. + @HotSpotIntrinsicCandidate + private void implDecryptBlock(byte[] in, int inOffset, + byte[] out, int outOffset) { int keyOffset = 4; int t0 = ((in[inOffset++] ) << 24 | @@ -572,6 +592,25 @@ final class AESCrypt extends SymmetricCipher implements AESConstants out[outOffset ] = (byte)(Si[(a0 ) & 0xFF] ^ (t1 )); } + // Used to perform all checks required by the Java semantics + // (i.e., null checks and bounds checks) on the input parameters + // to encryptBlock and to decryptBlock. + // Normally, the Java Runtime performs these checks, however, as + // encryptBlock and decryptBlock are possibly replaced with + // compiler intrinsics, the JDK performs the required checks instead. + // Does not check accesses to class-internal (private) arrays. + private static void cryptBlockCheck(byte[] array, int offset) { + Objects.requireNonNull(array); + + if (offset < 0 || offset >= array.length) { + throw new ArrayIndexOutOfBoundsException(offset); + } + + int largestIndex = offset + AES_BLOCK_SIZE - 1; + if (largestIndex < 0 || largestIndex >= array.length) { + throw new ArrayIndexOutOfBoundsException(largestIndex); + } + } /** * Expand a user-supplied key material into a session key. diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java index 515478821d3..f903754fb48 100644 --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java @@ -27,6 +27,9 @@ package com.sun.crypto.provider; import java.security.InvalidKeyException; import java.security.ProviderException; +import java.util.Objects; + +import jdk.internal.HotSpotIntrinsicCandidate; /** @@ -138,15 +141,22 @@ class CipherBlockChaining extends FeedbackCipher { * @return the length of the encrypted data */ int encrypt(byte[] plain, int plainOffset, int plainLen, - byte[] cipher, int cipherOffset) + byte[] cipher, int cipherOffset) { + cryptBlockSizeCheck(plainLen); + cryptNullAndBoundsCheck(plain, plainOffset, plainLen); + cryptNullAndBoundsCheck(cipher, cipherOffset, plainLen); + return implEncrypt(plain, plainOffset, plainLen, + cipher, cipherOffset); + } + + @HotSpotIntrinsicCandidate + private int implEncrypt(byte[] plain, int plainOffset, int plainLen, + byte[] cipher, int cipherOffset) { - if ((plainLen % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } int endIndex = plainOffset + plainLen; for (; plainOffset < endIndex; - plainOffset+=blockSize, cipherOffset += blockSize) { + plainOffset += blockSize, cipherOffset += blockSize) { for (int i = 0; i < blockSize; i++) { k[i] = (byte)(plain[i + plainOffset] ^ r[i]); } @@ -179,11 +189,17 @@ class CipherBlockChaining extends FeedbackCipher { * @return the length of the decrypted data */ int decrypt(byte[] cipher, int cipherOffset, int cipherLen, - byte[] plain, int plainOffset) + byte[] plain, int plainOffset) { + cryptBlockSizeCheck(cipherLen); + cryptNullAndBoundsCheck(cipher, cipherOffset, cipherLen); + cryptNullAndBoundsCheck(plain, plainOffset, cipherLen); + return implDecrypt(cipher, cipherOffset, cipherLen, plain, plainOffset); + } + + @HotSpotIntrinsicCandidate + private int implDecrypt(byte[] cipher, int cipherOffset, int cipherLen, + byte[] plain, int plainOffset) { - if ((cipherLen % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } int endIndex = cipherOffset + cipherLen; for (; cipherOffset < endIndex; @@ -196,4 +212,27 @@ class CipherBlockChaining extends FeedbackCipher { } return cipherLen; } + + private void cryptBlockSizeCheck(int len) { + if ((len % blockSize) != 0) { + throw new ProviderException("Internal error in input buffering"); + } + } + + private static void cryptNullAndBoundsCheck(byte[] array, int offset, int len) { + if (len <= 0) { + return; // not an error because cryptImpl/decryptImpl won't execute if len <= 0 + } + + Objects.requireNonNull(array); + + if (offset < 0 || offset >= array.length) { + throw new ArrayIndexOutOfBoundsException(offset); + } + + int endIndex = offset + len - 1; + if (endIndex < 0 || endIndex >= array.length) { + throw new ArrayIndexOutOfBoundsException(endIndex); + } + } } diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java index dc42e6bbfd9..d917bfdbdf3 100644 --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java @@ -31,6 +31,8 @@ package com.sun.crypto.provider; import java.security.ProviderException; +import jdk.internal.HotSpotIntrinsicCandidate; + /** * This class represents the GHASH function defined in NIST 800-38D * under section 6.4. It needs to be constructed w/ a hash subkey, i.e. @@ -227,6 +229,7 @@ final class GHASH { * the hotspot signature. This method and methods called by it, cannot * throw exceptions or allocate arrays as it will breaking intrinsics */ + @HotSpotIntrinsicCandidate private static void processBlocks(byte[] data, int inOfs, int blocks, long[] st, long[] subH) { int offset = inOfs; while (blocks > 0) { diff --git a/jdk/src/java.base/share/classes/java/lang/Boolean.java b/jdk/src/java.base/share/classes/java/lang/Boolean.java index 1e3a9d7cd05..b53995193f1 100644 --- a/jdk/src/java.base/share/classes/java/lang/Boolean.java +++ b/jdk/src/java.base/share/classes/java/lang/Boolean.java @@ -25,6 +25,8 @@ package java.lang; +import jdk.internal.HotSpotIntrinsicCandidate; + /** * The Boolean class wraps a value of the primitive type * {@code boolean} in an object. An object of type @@ -128,6 +130,7 @@ public final class Boolean implements java.io.Serializable, * * @return the primitive {@code boolean} value of this object. */ + @HotSpotIntrinsicCandidate public boolean booleanValue() { return value; } @@ -146,6 +149,7 @@ public final class Boolean implements java.io.Serializable, * @return a {@code Boolean} instance representing {@code b}. * @since 1.4 */ + @HotSpotIntrinsicCandidate public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); } diff --git a/jdk/src/java.base/share/classes/java/lang/Byte.java b/jdk/src/java.base/share/classes/java/lang/Byte.java index e2a0246c694..0ae3903ca7e 100644 --- a/jdk/src/java.base/share/classes/java/lang/Byte.java +++ b/jdk/src/java.base/share/classes/java/lang/Byte.java @@ -25,6 +25,8 @@ package java.lang; +import jdk.internal.HotSpotIntrinsicCandidate; + /** * * The {@code Byte} class wraps a value of primitive type {@code byte} @@ -98,6 +100,7 @@ public final class Byte extends Number implements Comparable { * @return a {@code Byte} instance representing {@code b}. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static Byte valueOf(byte b) { final int offset = 128; return ByteCache.cache[(int)b + offset]; @@ -320,6 +323,7 @@ public final class Byte extends Number implements Comparable { * Returns the value of this {@code Byte} as a * {@code byte}. */ + @HotSpotIntrinsicCandidate public byte byteValue() { return value; } diff --git a/jdk/src/java.base/share/classes/java/lang/Character.java b/jdk/src/java.base/share/classes/java/lang/Character.java index cb316f14730..6dd68aa9cb1 100644 --- a/jdk/src/java.base/share/classes/java/lang/Character.java +++ b/jdk/src/java.base/share/classes/java/lang/Character.java @@ -30,6 +30,8 @@ import java.util.Map; import java.util.HashMap; import java.util.Locale; +import jdk.internal.HotSpotIntrinsicCandidate; + /** * The {@code Character} class wraps a value of the primitive * type {@code char} in an object. An object of type @@ -4569,6 +4571,7 @@ class Character implements java.io.Serializable, Comparable { * @return a Character instance representing c. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static Character valueOf(char c) { if (c <= 127) { // must cache return CharacterCache.cache[(int)c]; @@ -4581,6 +4584,7 @@ class Character implements java.io.Serializable, Comparable { * @return the primitive {@code char} value represented by * this object. */ + @HotSpotIntrinsicCandidate public char charValue() { return value; } @@ -7181,6 +7185,7 @@ class Character implements java.io.Serializable, Comparable { * the bytes in the specified char value. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static char reverseBytes(char ch) { return (char) (((ch & 0xFF00) >> 8) | (ch << 8)); } diff --git a/jdk/src/java.base/share/classes/java/lang/Class.java b/jdk/src/java.base/share/classes/java/lang/Class.java index 3aefe6ee2fb..2e8a469e9ba 100644 --- a/jdk/src/java.base/share/classes/java/lang/Class.java +++ b/jdk/src/java.base/share/classes/java/lang/Class.java @@ -56,6 +56,7 @@ import java.util.HashMap; import java.util.Objects; import java.util.StringJoiner; import sun.misc.Unsafe; +import jdk.internal.HotSpotIntrinsicCandidate; import sun.reflect.CallerSensitive; import sun.reflect.ConstantPool; import sun.reflect.Reflection; @@ -502,6 +503,7 @@ public final class Class implements java.io.Serializable, * * @since 1.1 */ + @HotSpotIntrinsicCandidate public native boolean isInstance(Object obj); @@ -529,6 +531,7 @@ public final class Class implements java.io.Serializable, * null. * @since 1.1 */ + @HotSpotIntrinsicCandidate public native boolean isAssignableFrom(Class cls); @@ -539,6 +542,7 @@ public final class Class implements java.io.Serializable, * @return {@code true} if this object represents an interface; * {@code false} otherwise. */ + @HotSpotIntrinsicCandidate public native boolean isInterface(); @@ -549,6 +553,7 @@ public final class Class implements java.io.Serializable, * {@code false} otherwise. * @since 1.1 */ + @HotSpotIntrinsicCandidate public native boolean isArray(); @@ -580,6 +585,7 @@ public final class Class implements java.io.Serializable, * @see java.lang.Void#TYPE * @since 1.1 */ + @HotSpotIntrinsicCandidate public native boolean isPrimitive(); /** @@ -751,6 +757,7 @@ public final class Class implements java.io.Serializable, * * @return the direct superclass of the class represented by this object */ + @HotSpotIntrinsicCandidate public native Class getSuperclass(); @@ -984,6 +991,7 @@ public final class Class implements java.io.Serializable, * @see java.lang.reflect.Modifier * @since 1.1 */ + @HotSpotIntrinsicCandidate public native int getModifiers(); @@ -3382,6 +3390,7 @@ public final class Class implements java.io.Serializable, * @since 1.5 */ @SuppressWarnings("unchecked") + @HotSpotIntrinsicCandidate public T cast(Object obj) { if (obj != null && !isInstance(obj)) throw new ClassCastException(cannotCastMsg(obj)); diff --git a/jdk/src/java.base/share/classes/java/lang/Double.java b/jdk/src/java.base/share/classes/java/lang/Double.java index 11bda19da54..88201873c36 100644 --- a/jdk/src/java.base/share/classes/java/lang/Double.java +++ b/jdk/src/java.base/share/classes/java/lang/Double.java @@ -27,6 +27,7 @@ package java.lang; import sun.misc.FloatingDecimal; import sun.misc.DoubleConsts; +import jdk.internal.HotSpotIntrinsicCandidate; /** * The {@code Double} class wraps a value of the primitive type @@ -514,6 +515,7 @@ public final class Double extends Number implements Comparable { * @return a {@code Double} instance representing {@code d}. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static Double valueOf(double d) { return new Double(d); } @@ -711,6 +713,7 @@ public final class Double extends Number implements Comparable { * * @return the {@code double} value represented by this object */ + @HotSpotIntrinsicCandidate public double doubleValue() { return value; } @@ -831,6 +834,7 @@ public final class Double extends Number implements Comparable { * @param value a {@code double} precision floating-point number. * @return the bits that represent the floating-point number. */ + @HotSpotIntrinsicCandidate public static long doubleToLongBits(double value) { if (!isNaN(value)) { return doubleToRawLongBits(value); @@ -874,6 +878,7 @@ public final class Double extends Number implements Comparable { * @return the bits that represent the floating-point number. * @since 1.3 */ + @HotSpotIntrinsicCandidate public static native long doubleToRawLongBits(double value); /** @@ -937,6 +942,7 @@ public final class Double extends Number implements Comparable { * @return the {@code double} floating-point value with the same * bit pattern. */ + @HotSpotIntrinsicCandidate public static native double longBitsToDouble(long bits); /** diff --git a/jdk/src/java.base/share/classes/java/lang/Float.java b/jdk/src/java.base/share/classes/java/lang/Float.java index 0407b063c74..f9d3f9ef325 100644 --- a/jdk/src/java.base/share/classes/java/lang/Float.java +++ b/jdk/src/java.base/share/classes/java/lang/Float.java @@ -28,6 +28,7 @@ package java.lang; import sun.misc.FloatingDecimal; import sun.misc.FloatConsts; import sun.misc.DoubleConsts; +import jdk.internal.HotSpotIntrinsicCandidate; /** * The {@code Float} class wraps a value of primitive type @@ -429,6 +430,7 @@ public final class Float extends Number implements Comparable { * @return a {@code Float} instance representing {@code f}. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static Float valueOf(float f) { return new Float(f); } @@ -622,6 +624,7 @@ public final class Float extends Number implements Comparable { * * @return the {@code float} value represented by this object */ + @HotSpotIntrinsicCandidate public float floatValue() { return value; } @@ -740,6 +743,7 @@ public final class Float extends Number implements Comparable { * @param value a floating-point number. * @return the bits that represent the floating-point number. */ + @HotSpotIntrinsicCandidate public static int floatToIntBits(float value) { if (!isNaN(value)) { return floatToRawIntBits(value); @@ -782,6 +786,7 @@ public final class Float extends Number implements Comparable { * @return the bits that represent the floating-point number. * @since 1.3 */ + @HotSpotIntrinsicCandidate public static native int floatToRawIntBits(float value); /** @@ -843,6 +848,7 @@ public final class Float extends Number implements Comparable { * @return the {@code float} floating-point value with the same bit * pattern. */ + @HotSpotIntrinsicCandidate public static native float intBitsToFloat(int bits); /** diff --git a/jdk/src/java.base/share/classes/java/lang/Integer.java b/jdk/src/java.base/share/classes/java/lang/Integer.java index 35079175e1d..b3cfe9315ba 100644 --- a/jdk/src/java.base/share/classes/java/lang/Integer.java +++ b/jdk/src/java.base/share/classes/java/lang/Integer.java @@ -27,6 +27,7 @@ package java.lang; import java.lang.annotation.Native; import java.util.Objects; +import jdk.internal.HotSpotIntrinsicCandidate; /** * The {@code Integer} class wraps a value of the primitive type @@ -395,6 +396,7 @@ public final class Integer extends Number implements Comparable { * @param i an integer to be converted. * @return a string representation of the argument in base 10. */ + @HotSpotIntrinsicCandidate public static String toString(int i) { if (i == Integer.MIN_VALUE) return "-2147483648"; @@ -972,6 +974,7 @@ public final class Integer extends Number implements Comparable { * @return an {@code Integer} instance representing {@code i}. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; @@ -1035,6 +1038,7 @@ public final class Integer extends Number implements Comparable { * Returns the value of this {@code Integer} as an * {@code int}. */ + @HotSpotIntrinsicCandidate public int intValue() { return value; } @@ -1538,6 +1542,7 @@ public final class Integer extends Number implements Comparable { * is equal to zero. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static int numberOfLeadingZeros(int i) { // HD, Figure 5-6 if (i == 0) @@ -1565,6 +1570,7 @@ public final class Integer extends Number implements Comparable { * to zero. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static int numberOfTrailingZeros(int i) { // HD, Figure 5-14 int y; @@ -1587,6 +1593,7 @@ public final class Integer extends Number implements Comparable { * representation of the specified {@code int} value. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static int bitCount(int i) { // HD, Figure 5-2 i = i - ((i >>> 1) & 0x55555555); @@ -1688,6 +1695,7 @@ public final class Integer extends Number implements Comparable { * {@code int} value. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static int reverseBytes(int i) { return ((i >>> 24) ) | ((i >> 8) & 0xFF00) | diff --git a/jdk/src/java.base/share/classes/java/lang/Long.java b/jdk/src/java.base/share/classes/java/lang/Long.java index b1b37032397..4f248d71003 100644 --- a/jdk/src/java.base/share/classes/java/lang/Long.java +++ b/jdk/src/java.base/share/classes/java/lang/Long.java @@ -28,6 +28,7 @@ package java.lang; import java.lang.annotation.Native; import java.math.*; import java.util.Objects; +import jdk.internal.HotSpotIntrinsicCandidate; /** @@ -1074,6 +1075,7 @@ public final class Long extends Number implements Comparable { * @return a {@code Long} instance representing {@code l}. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static Long valueOf(long l) { final int offset = 128; if (l >= -128 && l <= 127) { // will cache @@ -1238,6 +1240,7 @@ public final class Long extends Number implements Comparable { * Returns the value of this {@code Long} as a * {@code long} value. */ + @HotSpotIntrinsicCandidate public long longValue() { return value; } @@ -1655,6 +1658,7 @@ public final class Long extends Number implements Comparable { * is equal to zero. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static int numberOfLeadingZeros(long i) { // HD, Figure 5-6 if (i == 0) @@ -1684,6 +1688,7 @@ public final class Long extends Number implements Comparable { * to zero. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static int numberOfTrailingZeros(long i) { // HD, Figure 5-14 int x, y; @@ -1707,6 +1712,7 @@ public final class Long extends Number implements Comparable { * representation of the specified {@code long} value. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static int bitCount(long i) { // HD, Figure 5-2 i = i - ((i >>> 1) & 0x5555555555555555L); @@ -1810,6 +1816,7 @@ public final class Long extends Number implements Comparable { * {@code long} value. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static long reverseBytes(long i) { i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL; return (i << 48) | ((i & 0xffff0000L) << 16) | diff --git a/jdk/src/java.base/share/classes/java/lang/Math.java b/jdk/src/java.base/share/classes/java/lang/Math.java index bc54bef83ea..1cd32bd3839 100644 --- a/jdk/src/java.base/share/classes/java/lang/Math.java +++ b/jdk/src/java.base/share/classes/java/lang/Math.java @@ -24,10 +24,11 @@ */ package java.lang; -import java.util.Random; +import java.util.Random; import sun.misc.FloatConsts; import sun.misc.DoubleConsts; +import jdk.internal.HotSpotIntrinsicCandidate; /** * The class {@code Math} contains methods for performing basic @@ -147,6 +148,7 @@ public final class Math { * @param a an angle, in radians. * @return the sine of the argument. */ + @HotSpotIntrinsicCandidate public static double sin(double a) { return StrictMath.sin(a); // default impl. delegates to StrictMath } @@ -162,6 +164,7 @@ public final class Math { * @param a an angle, in radians. * @return the cosine of the argument. */ + @HotSpotIntrinsicCandidate public static double cos(double a) { return StrictMath.cos(a); // default impl. delegates to StrictMath } @@ -179,6 +182,7 @@ public final class Math { * @param a an angle, in radians. * @return the tangent of the argument. */ + @HotSpotIntrinsicCandidate public static double tan(double a) { return StrictMath.tan(a); // default impl. delegates to StrictMath } @@ -280,6 +284,7 @@ public final class Math { * @return the value e{@code a}, * where e is the base of the natural logarithms. */ + @HotSpotIntrinsicCandidate public static double exp(double a) { return StrictMath.exp(a); // default impl. delegates to StrictMath } @@ -301,6 +306,7 @@ public final class Math { * @return the value ln {@code a}, the natural logarithm of * {@code a}. */ + @HotSpotIntrinsicCandidate public static double log(double a) { return StrictMath.log(a); // default impl. delegates to StrictMath } @@ -326,6 +332,7 @@ public final class Math { * @return the base 10 logarithm of {@code a}. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static double log10(double a) { return StrictMath.log10(a); // default impl. delegates to StrictMath } @@ -347,6 +354,7 @@ public final class Math { * @return the positive square root of {@code a}. * If the argument is NaN or less than zero, the result is NaN. */ + @HotSpotIntrinsicCandidate public static double sqrt(double a) { return StrictMath.sqrt(a); // default impl. delegates to StrictMath // Note that hardware sqrt instructions @@ -525,6 +533,7 @@ public final class Math { * in polar coordinates that corresponds to the point * (xy) in Cartesian coordinates. */ + @HotSpotIntrinsicCandidate public static double atan2(double y, double x) { return StrictMath.atan2(y, x); // default impl. delegates to StrictMath } @@ -652,6 +661,7 @@ public final class Math { * @param b the exponent. * @return the value {@code a}{@code b}. */ + @HotSpotIntrinsicCandidate public static double pow(double a, double b) { return StrictMath.pow(a, b); // default impl. delegates to StrictMath } @@ -806,6 +816,7 @@ public final class Math { * @throws ArithmeticException if the result overflows an int * @since 1.8 */ + @HotSpotIntrinsicCandidate public static int addExact(int x, int y) { int r = x + y; // HD 2-12 Overflow iff both arguments have the opposite sign of the result @@ -825,6 +836,7 @@ public final class Math { * @throws ArithmeticException if the result overflows a long * @since 1.8 */ + @HotSpotIntrinsicCandidate public static long addExact(long x, long y) { long r = x + y; // HD 2-12 Overflow iff both arguments have the opposite sign of the result @@ -844,6 +856,7 @@ public final class Math { * @throws ArithmeticException if the result overflows an int * @since 1.8 */ + @HotSpotIntrinsicCandidate public static int subtractExact(int x, int y) { int r = x - y; // HD 2-12 Overflow iff the arguments have different signs and @@ -864,6 +877,7 @@ public final class Math { * @throws ArithmeticException if the result overflows a long * @since 1.8 */ + @HotSpotIntrinsicCandidate public static long subtractExact(long x, long y) { long r = x - y; // HD 2-12 Overflow iff the arguments have different signs and @@ -884,6 +898,7 @@ public final class Math { * @throws ArithmeticException if the result overflows an int * @since 1.8 */ + @HotSpotIntrinsicCandidate public static int multiplyExact(int x, int y) { long r = (long)x * (long)y; if ((int)r != r) { @@ -902,6 +917,7 @@ public final class Math { * @throws ArithmeticException if the result overflows a long * @since 1.8 */ + @HotSpotIntrinsicCandidate public static long multiplyExact(long x, long y) { long r = x * y; long ax = Math.abs(x); @@ -927,6 +943,7 @@ public final class Math { * @throws ArithmeticException if the result overflows an int * @since 1.8 */ + @HotSpotIntrinsicCandidate public static int incrementExact(int a) { if (a == Integer.MAX_VALUE) { throw new ArithmeticException("integer overflow"); @@ -944,6 +961,7 @@ public final class Math { * @throws ArithmeticException if the result overflows a long * @since 1.8 */ + @HotSpotIntrinsicCandidate public static long incrementExact(long a) { if (a == Long.MAX_VALUE) { throw new ArithmeticException("long overflow"); @@ -961,6 +979,7 @@ public final class Math { * @throws ArithmeticException if the result overflows an int * @since 1.8 */ + @HotSpotIntrinsicCandidate public static int decrementExact(int a) { if (a == Integer.MIN_VALUE) { throw new ArithmeticException("integer overflow"); @@ -978,6 +997,7 @@ public final class Math { * @throws ArithmeticException if the result overflows a long * @since 1.8 */ + @HotSpotIntrinsicCandidate public static long decrementExact(long a) { if (a == Long.MIN_VALUE) { throw new ArithmeticException("long overflow"); @@ -995,6 +1015,7 @@ public final class Math { * @throws ArithmeticException if the result overflows an int * @since 1.8 */ + @HotSpotIntrinsicCandidate public static int negateExact(int a) { if (a == Integer.MIN_VALUE) { throw new ArithmeticException("integer overflow"); @@ -1012,6 +1033,7 @@ public final class Math { * @throws ArithmeticException if the result overflows a long * @since 1.8 */ + @HotSpotIntrinsicCandidate public static long negateExact(long a) { if (a == Long.MIN_VALUE) { throw new ArithmeticException("long overflow"); @@ -1256,6 +1278,7 @@ public final class Math { * @param a the argument whose absolute value is to be determined * @return the absolute value of the argument. */ + @HotSpotIntrinsicCandidate public static double abs(double a) { return (a <= 0.0D) ? 0.0D - a : a; } @@ -1270,6 +1293,7 @@ public final class Math { * @param b another argument. * @return the larger of {@code a} and {@code b}. */ + @HotSpotIntrinsicCandidate public static int max(int a, int b) { return (a >= b) ? a : b; } @@ -1354,6 +1378,7 @@ public final class Math { * @param b another argument. * @return the smaller of {@code a} and {@code b}. */ + @HotSpotIntrinsicCandidate public static int min(int a, int b) { return (a <= b) ? a : b; } diff --git a/jdk/src/java.base/share/classes/java/lang/Object.java b/jdk/src/java.base/share/classes/java/lang/Object.java index 2eeac24a688..aa3318463c3 100644 --- a/jdk/src/java.base/share/classes/java/lang/Object.java +++ b/jdk/src/java.base/share/classes/java/lang/Object.java @@ -25,6 +25,8 @@ package java.lang; +import jdk.internal.HotSpotIntrinsicCandidate; + /** * Class {@code Object} is the root of the class hierarchy. * Every class has {@code Object} as a superclass. All objects, @@ -44,6 +46,7 @@ public class Object { /** * Constructs a new object. */ + @HotSpotIntrinsicCandidate public Object() {} /** @@ -65,6 +68,7 @@ public class Object { * class of this object. * @jls 15.8.2 Class Literals */ + @HotSpotIntrinsicCandidate public final native Class getClass(); /** @@ -101,6 +105,7 @@ public class Object { * @see java.lang.Object#equals(java.lang.Object) * @see java.lang.System#identityHashCode */ + @HotSpotIntrinsicCandidate public native int hashCode(); /** @@ -213,6 +218,7 @@ public class Object { * be cloned. * @see java.lang.Cloneable */ + @HotSpotIntrinsicCandidate protected native Object clone() throws CloneNotSupportedException; /** diff --git a/jdk/src/java.base/share/classes/java/lang/Short.java b/jdk/src/java.base/share/classes/java/lang/Short.java index e6a6c75e0ec..6cc4d17d35a 100644 --- a/jdk/src/java.base/share/classes/java/lang/Short.java +++ b/jdk/src/java.base/share/classes/java/lang/Short.java @@ -25,6 +25,8 @@ package java.lang; +import jdk.internal.HotSpotIntrinsicCandidate; + /** * The {@code Short} class wraps a value of primitive type {@code * short} in an object. An object of type {@code Short} contains a @@ -227,6 +229,7 @@ public final class Short extends Number implements Comparable { * @return a {@code Short} instance representing {@code s}. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static Short valueOf(short s) { final int offset = 128; int sAsInt = s; @@ -334,6 +337,7 @@ public final class Short extends Number implements Comparable { * Returns the value of this {@code Short} as a * {@code short}. */ + @HotSpotIntrinsicCandidate public short shortValue() { return value; } @@ -487,6 +491,7 @@ public final class Short extends Number implements Comparable { * the bytes in the specified {@code short} value. * @since 1.5 */ + @HotSpotIntrinsicCandidate public static short reverseBytes(short i) { return (short) (((i & 0xFF00) >> 8) | (i << 8)); } diff --git a/jdk/src/java.base/share/classes/java/lang/StrictMath.java b/jdk/src/java.base/share/classes/java/lang/StrictMath.java index ffb9f62fce9..34cadb1a2ca 100644 --- a/jdk/src/java.base/share/classes/java/lang/StrictMath.java +++ b/jdk/src/java.base/share/classes/java/lang/StrictMath.java @@ -24,8 +24,10 @@ */ package java.lang; + import java.util.Random; import sun.misc.DoubleConsts; +import jdk.internal.HotSpotIntrinsicCandidate; /** * The class {@code StrictMath} contains methods for performing basic @@ -243,7 +245,6 @@ public final class StrictMath { */ public static native double log(double a); - /** * Returns the base 10 logarithm of a {@code double} value. * Special cases: @@ -280,6 +281,7 @@ public final class StrictMath { * @param a a value. * @return the positive square root of {@code a}. */ + @HotSpotIntrinsicCandidate public static native double sqrt(double a); /** @@ -521,7 +523,6 @@ public final class StrictMath { */ public static native double atan2(double y, double x); - /** * Returns the value of the first argument raised to the power of the * second argument. Special cases: @@ -1009,6 +1010,7 @@ public final class StrictMath { * @param b another argument. * @return the larger of {@code a} and {@code b}. */ + @HotSpotIntrinsicCandidate public static int max(int a, int b) { return Math.max(a, b); } @@ -1073,6 +1075,7 @@ public final class StrictMath { * @param b another argument. * @return the smaller of {@code a} and {@code b}. */ + @HotSpotIntrinsicCandidate public static int min(int a, int b) { return Math.min(a, b); } diff --git a/jdk/src/java.base/share/classes/java/lang/String.java b/jdk/src/java.base/share/classes/java/lang/String.java index 7c42d59ea14..9e0225f947d 100644 --- a/jdk/src/java.base/share/classes/java/lang/String.java +++ b/jdk/src/java.base/share/classes/java/lang/String.java @@ -42,6 +42,7 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import java.util.stream.IntStream; import java.util.stream.StreamSupport; +import jdk.internal.HotSpotIntrinsicCandidate; /** * The {@code String} class represents character strings. All @@ -152,6 +153,7 @@ public final class String * @param original * A {@code String} */ + @HotSpotIntrinsicCandidate public String(String original) { this.value = original.value; this.hash = original.hash; @@ -978,6 +980,7 @@ public final class String * @see #compareTo(String) * @see #equalsIgnoreCase(String) */ + @HotSpotIntrinsicCandidate public boolean equals(Object anObject) { if (this == anObject) { return true; @@ -1154,6 +1157,7 @@ public final class String * value greater than {@code 0} if this string is * lexicographically greater than the string argument. */ + @HotSpotIntrinsicCandidate public int compareTo(String anotherString) { char[] v1 = value; char[] v2 = anotherString.value; @@ -1696,6 +1700,7 @@ public final class String * @return the index of the first occurrence of the specified substring, * or {@code -1} if there is no such occurrence. */ + @HotSpotIntrinsicCandidate public int indexOf(String str) { return indexOf(str, 0); } diff --git a/jdk/src/java.base/share/classes/java/lang/StringBuffer.java b/jdk/src/java.base/share/classes/java/lang/StringBuffer.java index 80d6718399f..a20645463fa 100644 --- a/jdk/src/java.base/share/classes/java/lang/StringBuffer.java +++ b/jdk/src/java.base/share/classes/java/lang/StringBuffer.java @@ -26,6 +26,7 @@ package java.lang; import java.util.Arrays; +import jdk.internal.HotSpotIntrinsicCandidate; /** * A thread-safe, mutable sequence of characters. @@ -112,6 +113,7 @@ import java.util.Arrays; * Constructs a string buffer with no characters in it and an * initial capacity of 16 characters. */ + @HotSpotIntrinsicCandidate public StringBuffer() { super(16); } @@ -124,6 +126,7 @@ import java.util.Arrays; * @exception NegativeArraySizeException if the {@code capacity} * argument is less than {@code 0}. */ + @HotSpotIntrinsicCandidate public StringBuffer(int capacity) { super(capacity); } @@ -135,6 +138,7 @@ import java.util.Arrays; * * @param str the initial contents of the buffer. */ + @HotSpotIntrinsicCandidate public StringBuffer(String str) { super(str.length() + 16); append(str); @@ -271,6 +275,7 @@ import java.util.Arrays; } @Override + @HotSpotIntrinsicCandidate public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); @@ -382,6 +387,7 @@ import java.util.Arrays; } @Override + @HotSpotIntrinsicCandidate public synchronized StringBuffer append(char c) { toStringCache = null; super.append(c); @@ -389,6 +395,7 @@ import java.util.Arrays; } @Override + @HotSpotIntrinsicCandidate public synchronized StringBuffer append(int i) { toStringCache = null; super.append(i); @@ -670,6 +677,7 @@ import java.util.Arrays; } @Override + @HotSpotIntrinsicCandidate public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); diff --git a/jdk/src/java.base/share/classes/java/lang/StringBuilder.java b/jdk/src/java.base/share/classes/java/lang/StringBuilder.java index f73f8a206c7..9d4ccf3dbbe 100644 --- a/jdk/src/java.base/share/classes/java/lang/StringBuilder.java +++ b/jdk/src/java.base/share/classes/java/lang/StringBuilder.java @@ -25,6 +25,7 @@ package java.lang; +import jdk.internal.HotSpotIntrinsicCandidate; /** * A mutable sequence of characters. This class provides an API compatible @@ -85,6 +86,7 @@ public final class StringBuilder * Constructs a string builder with no characters in it and an * initial capacity of 16 characters. */ + @HotSpotIntrinsicCandidate public StringBuilder() { super(16); } @@ -97,6 +99,7 @@ public final class StringBuilder * @throws NegativeArraySizeException if the {@code capacity} * argument is less than {@code 0}. */ + @HotSpotIntrinsicCandidate public StringBuilder(int capacity) { super(capacity); } @@ -108,6 +111,7 @@ public final class StringBuilder * * @param str the initial contents of the buffer. */ + @HotSpotIntrinsicCandidate public StringBuilder(String str) { super(str.length() + 16); append(str); @@ -132,6 +136,7 @@ public final class StringBuilder } @Override + @HotSpotIntrinsicCandidate public StringBuilder append(String str) { super.append(str); return this; @@ -198,12 +203,14 @@ public final class StringBuilder } @Override + @HotSpotIntrinsicCandidate public StringBuilder append(char c) { super.append(c); return this; } @Override + @HotSpotIntrinsicCandidate public StringBuilder append(int i) { super.append(i); return this; @@ -402,6 +409,7 @@ public final class StringBuilder } @Override + @HotSpotIntrinsicCandidate public String toString() { // Create a copy, don't share the array return new String(value, 0, count); diff --git a/jdk/src/java.base/share/classes/java/lang/System.java b/jdk/src/java.base/share/classes/java/lang/System.java index 699467ca5a4..aef3cf1231f 100644 --- a/jdk/src/java.base/share/classes/java/lang/System.java +++ b/jdk/src/java.base/share/classes/java/lang/System.java @@ -42,6 +42,7 @@ import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; import sun.reflect.annotation.AnnotationType; +import jdk.internal.HotSpotIntrinsicCandidate; /** * The System class contains several useful class fields @@ -349,6 +350,7 @@ public final class System { * the current time and midnight, January 1, 1970 UTC. * @see java.util.Date */ + @HotSpotIntrinsicCandidate public static native long currentTimeMillis(); /** @@ -392,6 +394,7 @@ public final class System { * high-resolution time source, in nanoseconds * @since 1.5 */ + @HotSpotIntrinsicCandidate public static native long nanoTime(); /** @@ -486,6 +489,7 @@ public final class System { * @exception NullPointerException if either src or * dest is null. */ + @HotSpotIntrinsicCandidate public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); @@ -501,6 +505,7 @@ public final class System { * @return the hashCode * @since 1.1 */ + @HotSpotIntrinsicCandidate public static native int identityHashCode(Object x); /** diff --git a/jdk/src/java.base/share/classes/java/lang/Thread.java b/jdk/src/java.base/share/classes/java/lang/Thread.java index af2a2a2b049..05953b3b520 100644 --- a/jdk/src/java.base/share/classes/java/lang/Thread.java +++ b/jdk/src/java.base/share/classes/java/lang/Thread.java @@ -40,7 +40,7 @@ import sun.nio.ch.Interruptible; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; - +import jdk.internal.HotSpotIntrinsicCandidate; /** * A thread is a thread of execution in a program. The Java @@ -261,6 +261,7 @@ class Thread implements Runnable { * * @return the currently executing thread. */ + @HotSpotIntrinsicCandidate public static native Thread currentThread(); /** @@ -966,6 +967,7 @@ class Thread implements Runnable { * is reset or not based on the value of ClearInterrupted that is * passed. */ + @HotSpotIntrinsicCandidate private native boolean isInterrupted(boolean ClearInterrupted); /** diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index cb621b60e82..67017b6b02a 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -27,6 +27,7 @@ package java.lang.invoke; import java.util.*; +import jdk.internal.HotSpotIntrinsicCandidate; import static java.lang.invoke.MethodHandleStatics.*; @@ -476,6 +477,7 @@ public abstract class MethodHandle { * @throws WrongMethodTypeException if the target's type is not identical with the caller's symbolic type descriptor * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call */ + @HotSpotIntrinsicCandidate public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable; /** @@ -513,6 +515,7 @@ public abstract class MethodHandle { * @throws ClassCastException if the target's type can be adjusted to the caller, but a reference cast fails * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call */ + @HotSpotIntrinsicCandidate public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable; /** @@ -532,6 +535,7 @@ public abstract class MethodHandle { * @param args the signature-polymorphic parameter list, statically represented using varargs * @return the signature-polymorphic result, statically represented using {@code Object} */ + @HotSpotIntrinsicCandidate /*non-public*/ final native @PolymorphicSignature Object invokeBasic(Object... args) throws Throwable; /** @@ -541,6 +545,7 @@ public abstract class MethodHandle { * @param args the signature-polymorphic parameter list, statically represented using varargs * @return the signature-polymorphic result, statically represented using {@code Object} */ + @HotSpotIntrinsicCandidate /*non-public*/ static native @PolymorphicSignature Object linkToVirtual(Object... args) throws Throwable; /** @@ -550,6 +555,7 @@ public abstract class MethodHandle { * @param args the signature-polymorphic parameter list, statically represented using varargs * @return the signature-polymorphic result, statically represented using {@code Object} */ + @HotSpotIntrinsicCandidate /*non-public*/ static native @PolymorphicSignature Object linkToStatic(Object... args) throws Throwable; /** @@ -559,6 +565,7 @@ public abstract class MethodHandle { * @param args the signature-polymorphic parameter list, statically represented using varargs * @return the signature-polymorphic result, statically represented using {@code Object} */ + @HotSpotIntrinsicCandidate /*non-public*/ static native @PolymorphicSignature Object linkToSpecial(Object... args) throws Throwable; /** @@ -568,6 +575,7 @@ public abstract class MethodHandle { * @param args the signature-polymorphic parameter list, statically represented using varargs * @return the signature-polymorphic result, statically represented using {@code Object} */ + @HotSpotIntrinsicCandidate /*non-public*/ static native @PolymorphicSignature Object linkToInterface(Object... args) throws Throwable; /** diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index d1c1d6984f8..4de3439d0a4 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -36,6 +36,7 @@ import sun.invoke.empty.Empty; import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyType; import sun.invoke.util.Wrapper; +import jdk.internal.HotSpotIntrinsicCandidate; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import static java.lang.invoke.LambdaForm.*; @@ -709,6 +710,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; // Intrinsified by C2. Counters are used during parsing to calculate branch frequencies. @LambdaForm.Hidden + @jdk.internal.HotSpotIntrinsicCandidate static boolean profileBoolean(boolean result, int[] counters) { // Profile is int[2] where [0] and [1] correspond to false and true occurrences respectively. @@ -724,6 +726,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; // Intrinsified by C2. Returns true if obj is a compile-time constant. @LambdaForm.Hidden + @jdk.internal.HotSpotIntrinsicCandidate static boolean isCompileConstant(Object obj) { return false; diff --git a/jdk/src/java.base/share/classes/java/lang/ref/Reference.java b/jdk/src/java.base/share/classes/java/lang/ref/Reference.java index 2bab588f1f4..7f6456f0947 100644 --- a/jdk/src/java.base/share/classes/java/lang/ref/Reference.java +++ b/jdk/src/java.base/share/classes/java/lang/ref/Reference.java @@ -29,6 +29,7 @@ import sun.misc.Cleaner; import sun.misc.JavaLangRefAccess; import sun.misc.ManagedLocalsThread; import sun.misc.SharedSecrets; +import jdk.internal.HotSpotIntrinsicCandidate; /** * Abstract base class for reference objects. This class defines the @@ -251,6 +252,7 @@ public abstract class Reference { * @return The object to which this reference refers, or * null if this reference object has been cleared */ + @HotSpotIntrinsicCandidate public T get() { return this.referent; } diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Array.java b/jdk/src/java.base/share/classes/java/lang/reflect/Array.java index 7e7e3560362..2d6d717ad15 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Array.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Array.java @@ -25,6 +25,8 @@ package java.lang.reflect; +import jdk.internal.HotSpotIntrinsicCandidate; + /** * The {@code Array} class provides static methods to dynamically create and * access Java arrays. @@ -119,6 +121,7 @@ class Array { * @exception IllegalArgumentException if the object argument is not * an array */ + @HotSpotIntrinsicCandidate public static native int getLength(Object array) throws IllegalArgumentException; @@ -477,6 +480,7 @@ class Array { * Private */ + @HotSpotIntrinsicCandidate private static native Object newArray(Class componentType, int length) throws NegativeArraySizeException; diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java index 27bbd91a3ac..ce710c0ef5b 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java @@ -25,6 +25,7 @@ package java.lang.reflect; +import jdk.internal.HotSpotIntrinsicCandidate; import sun.reflect.CallerSensitive; import sun.reflect.MethodAccessor; import sun.reflect.Reflection; @@ -485,6 +486,7 @@ public final class Method extends Executable { * provoked by this method fails. */ @CallerSensitive + @HotSpotIntrinsicCandidate public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException diff --git a/jdk/src/java.base/share/classes/java/math/BigInteger.java b/jdk/src/java.base/share/classes/java/math/BigInteger.java index 51ed2b6abbf..201fce2575b 100644 --- a/jdk/src/java.base/share/classes/java/math/BigInteger.java +++ b/jdk/src/java.base/share/classes/java/math/BigInteger.java @@ -34,10 +34,13 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.util.Arrays; +import java.util.Objects; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; + import sun.misc.DoubleConsts; import sun.misc.FloatConsts; +import jdk.internal.HotSpotIntrinsicCandidate; /** * Immutable arbitrary-precision integers. All operations behave as if @@ -1649,6 +1652,13 @@ public class BigInteger extends Number implements Comparable { * the result into z. There will be no leading zeros in the resultant array. */ private static int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) { + multiplyToLenCheck(x, xlen); + multiplyToLenCheck(y, ylen); + return implMultiplyToLen(x, xlen, y, ylen, z); + } + + @HotSpotIntrinsicCandidate + private static int[] implMultiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) { int xstart = xlen - 1; int ystart = ylen - 1; @@ -1678,6 +1688,18 @@ public class BigInteger extends Number implements Comparable { return z; } + private static void multiplyToLenCheck(int[] array, int length) { + if (length <= 0) { + return; // not an error because multiplyToLen won't execute if len <= 0 + } + + Objects.requireNonNull(array); + + if (length > array.length) { + throw new ArrayIndexOutOfBoundsException(length - 1); + } + } + /** * Multiplies two BigIntegers using the Karatsuba multiplication * algorithm. This is a recursive divide-and-conquer algorithm which is @@ -2008,6 +2030,7 @@ public class BigInteger extends Number implements Comparable { /** * Java Runtime may use intrinsic for this method. */ + @HotSpotIntrinsicCandidate private static final int[] implSquareToLen(int[] x, int len, int[] z, int zlen) { /* * The algorithm used here is adapted from Colin Plumb's C library. @@ -2668,11 +2691,13 @@ public class BigInteger extends Number implements Comparable { // These methods are intended to be be replaced by virtual machine // intrinsics. + @HotSpotIntrinsicCandidate private static int[] implMontgomeryMultiply(int[] a, int[] b, int[] n, int len, long inv, int[] product) { product = multiplyToLen(a, len, b, len, product); return montReduce(product, n, len, (int)inv); } + @HotSpotIntrinsicCandidate private static int[] implMontgomerySquare(int[] a, int[] n, int len, long inv, int[] product) { product = squareToLen(a, len, product); @@ -3004,6 +3029,7 @@ public class BigInteger extends Number implements Comparable { /** * Java Runtime may use intrinsic for this method. */ + @HotSpotIntrinsicCandidate private static int implMulAdd(int[] out, int[] in, int offset, int len, int k) { long kLong = k & LONG_MASK; long carry = 0; diff --git a/jdk/src/java.base/share/classes/java/nio/Buffer.java b/jdk/src/java.base/share/classes/java/nio/Buffer.java index 37d8aa0786c..58b451675bf 100644 --- a/jdk/src/java.base/share/classes/java/nio/Buffer.java +++ b/jdk/src/java.base/share/classes/java/nio/Buffer.java @@ -26,6 +26,7 @@ package java.nio; import java.util.Spliterator; +import jdk.internal.HotSpotIntrinsicCandidate; /** * A container for data of a specific primitive type. @@ -535,6 +536,7 @@ public abstract class Buffer { * IndexOutOfBoundsException} if it is not smaller than the limit * or is smaller than zero. */ + @HotSpotIntrinsicCandidate final int checkIndex(int i) { // package-private if ((i < 0) || (i >= limit)) throw new IndexOutOfBoundsException(); diff --git a/jdk/src/java.base/share/classes/java/util/Arrays.java b/jdk/src/java.base/share/classes/java/util/Arrays.java index ae321498dc4..227a8ee078b 100644 --- a/jdk/src/java.base/share/classes/java/util/Arrays.java +++ b/jdk/src/java.base/share/classes/java/util/Arrays.java @@ -42,6 +42,7 @@ import java.util.stream.IntStream; import java.util.stream.LongStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.internal.HotSpotIntrinsicCandidate; /** * This class contains various methods for manipulating arrays (such as @@ -2654,6 +2655,7 @@ public class Arrays { * @param a2 the other array to be tested for equality * @return true if the two arrays are equal */ + @HotSpotIntrinsicCandidate public static boolean equals(char[] a, char[] a2) { if (a==a2) return true; @@ -3205,6 +3207,7 @@ public class Arrays { * an array of class newType * @since 1.6 */ + @HotSpotIntrinsicCandidate public static T[] copyOf(U[] original, int newLength, Class newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) @@ -3474,6 +3477,7 @@ public class Arrays { * an array of class newType. * @since 1.6 */ + @HotSpotIntrinsicCandidate public static T[] copyOfRange(U[] original, int from, int to, Class newType) { int newLength = to - from; if (newLength < 0) diff --git a/jdk/src/java.base/share/classes/java/util/stream/Streams.java b/jdk/src/java.base/share/classes/java/util/stream/Streams.java index 072691aeccb..38a3beee85b 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/Streams.java +++ b/jdk/src/java.base/share/classes/java/util/stream/Streams.java @@ -31,6 +31,7 @@ import java.util.function.Consumer; import java.util.function.DoubleConsumer; import java.util.function.IntConsumer; import java.util.function.LongConsumer; +import jdk.internal.HotSpotIntrinsicCandidate; /** * Utility methods for operating on and creating streams. @@ -98,6 +99,7 @@ final class Streams { } @Override + @HotSpotIntrinsicCandidate public void forEachRemaining(IntConsumer consumer) { Objects.requireNonNull(consumer); diff --git a/jdk/src/java.base/share/classes/java/util/zip/CRC32.java b/jdk/src/java.base/share/classes/java/util/zip/CRC32.java index 95ead3c3533..a259ccfc7e5 100644 --- a/jdk/src/java.base/share/classes/java/util/zip/CRC32.java +++ b/jdk/src/java.base/share/classes/java/util/zip/CRC32.java @@ -26,7 +26,10 @@ package java.util.zip; import java.nio.ByteBuffer; +import java.util.Objects; + import sun.nio.ch.DirectBuffer; +import jdk.internal.HotSpotIntrinsicCandidate; /** * A class that can be used to compute the CRC-32 of a data stream. @@ -123,9 +126,49 @@ class CRC32 implements Checksum { return (long)crc & 0xffffffffL; } + @HotSpotIntrinsicCandidate private native static int update(int crc, int b); - private native static int updateBytes(int crc, byte[] b, int off, int len); - private native static int updateByteBuffer(int adler, long addr, - int off, int len); + private static int updateBytes(int crc, byte[] b, int off, int len) { + updateBytesCheck(b, off, len); + return updateBytes0(crc, b, off, len); + } + + @HotSpotIntrinsicCandidate + private native static int updateBytes0(int crc, byte[] b, int off, int len); + + private static void updateBytesCheck(byte[] b, int off, int len) { + if (len <= 0) { + return; // not an error because updateBytesImpl won't execute if len <= 0 + } + + Objects.requireNonNull(b); + + if (off < 0 || off >= b.length) { + throw new ArrayIndexOutOfBoundsException(off); + } + + int endIndex = off + len - 1; + if (endIndex < 0 || endIndex >= b.length) { + throw new ArrayIndexOutOfBoundsException(endIndex); + } + } + + private static int updateByteBuffer(int alder, long addr, + int off, int len) { + updateByteBufferCheck(addr); + return updateByteBuffer0(alder, addr, off, len); + } + + @HotSpotIntrinsicCandidate + private native static int updateByteBuffer0(int alder, long addr, + int off, int len); + + private static void updateByteBufferCheck(long addr) { + // Performs only a null check because bounds checks + // are not easy to do on raw addresses. + if (addr == 0L) { + throw new NullPointerException(); + } + } } diff --git a/jdk/src/java.base/share/classes/java/util/zip/CRC32C.java b/jdk/src/java.base/share/classes/java/util/zip/CRC32C.java index ee690ac1bbd..c40886fafa6 100644 --- a/jdk/src/java.base/share/classes/java/util/zip/CRC32C.java +++ b/jdk/src/java.base/share/classes/java/util/zip/CRC32C.java @@ -26,6 +26,8 @@ package java.util.zip; import java.nio.ByteBuffer; import java.nio.ByteOrder; + +import jdk.internal.HotSpotIntrinsicCandidate; import sun.misc.Unsafe; import sun.nio.ch.DirectBuffer; @@ -204,6 +206,7 @@ public final class CRC32C implements Checksum { /** * Updates the CRC-32C checksum with the specified array of bytes. */ + @HotSpotIntrinsicCandidate private static int updateBytes(int crc, byte[] b, int off, int end) { // Do only byte reads for arrays so short they can't be aligned @@ -278,6 +281,7 @@ public final class CRC32C implements Checksum { /** * Updates the CRC-32C checksum reading from the specified address. */ + @HotSpotIntrinsicCandidate private static int updateDirectByteBuffer(int crc, long address, int off, int end) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/HotSpotIntrinsicCandidate.java b/jdk/src/java.base/share/classes/jdk/internal/HotSpotIntrinsicCandidate.java new file mode 100644 index 00000000000..e3efada1a7c --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/HotSpotIntrinsicCandidate.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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; + +import java.lang.annotation.*; + +/** + * The {@code @HotSpotIntrinsicCandidate} annotation is specific to the Oracle Java + * HotSpot Virtual Machine implementation and indicates that an annotated method + * may be (but is not guaranteed to be) intrinsified by the HotSpot VM. A method + * is intrinsified if the HotSpot VM replaces the annotated method with hand-written + * assembly and/or hand-written compiler IR -- a compiler intrinsic -- to improve + * performance. The {@code @HotSpotIntrinsicCandidate} annotation is internal to the + * Java libraries and is therefore not supposed to have any relevance for application + * code. + * + * Maintainers of the Java libraries must consider the following when + * modifying methods annotated with {@code @HotSpotIntrinsicCandidate}. + * + *
    + *
  • When modifying a method annotated with {@code @HotSpotIntrinsicCandidate}, + * the corresponding intrinsic code in the HotSpot VM implementation must be + * updated to match the semantics of the annotated method.
  • + *
  • For some annotated methods, the corresponding intrinsic may omit some low-level + * checks that would be performed as a matter of course if the intrinsic is implemented + * using Java bytecodes. This is because individual Java bytecodes implicitly check + * for exceptions like {@code NullPointerException} and {@code ArrayStoreException}. + * If such a method is replaced by an intrinsic coded in assembly language, any + * checks performed as a matter of normal bytecode operation must be performed + * before entry into the assembly code. These checks must be performed, as + * appropriate, on all arguments to the intrinsic, and on other values (if any) obtained + * by the intrinsic through those arguments. The checks may be deduced by inspecting + * the non-intrinsic Java code for the method, and determining exactly which exceptions + * may be thrown by the code, including undeclared implicit {@code RuntimeException}s. + * Therefore, depending on the data accesses performed by the intrinsic, + * the checks may include: + * + *
      + *
    • null checks on references
    • + *
    • range checks on primitive values used as array indexes
    • + *
    • other validity checks on primitive values (e.g., for divide-by-zero conditions)
    • + *
    • store checks on reference values stored into arrays
    • + *
    • array length checks on arrays indexed from within the intrinsic
    • + *
    • reference casts (when formal parameters are {@code Object} or some other weak type)
    • + *
    + * + *
  • + * + *
  • Note that the receiver value ({@code this}) is passed as a extra argument + * to all non-static methods. If a non-static method is an intrinsic, the receiver + * value does not need a null check, but (as stated above) any values loaded by the + * intrinsic from object fields must also be checked. As a matter of clarity, it is + * better to make intrinisics be static methods, to make the dependency on {@code this} + * clear. Also, it is better to explicitly load all required values from object + * fields before entering the intrinsic code, and pass those values as explicit arguments. + * First, this may be necessary for null checks (or other checks). Second, if the + * intrinsic reloads the values from fields and operates on those without checks, + * race conditions may be able to introduce unchecked invalid values into the intrinsic. + * If the intrinsic needs to store a value back to an object field, that value should be + * returned explicitly from the intrinsic; if there are multiple return values, coders + * should consider buffering them in an array. Removing field access from intrinsics + * not only clarifies the interface with between the JVM and JDK; it also helps decouple + * the HotSpot and JDK implementations, since if JDK code before and after the intrinsic + * manages all field accesses, then intrinsics can be coded to be agnostic of object + * layouts.
  • + * + * Maintainers of the HotSpot VM must consider the following when modifying + * intrinsics. + * + *
      + *
    • When adding a new intrinsic, make sure that the corresponding method + * in the Java libraries is annotated with {@code @HotSpotIntrinsicCandidate} + * and that all possible call sequences that result in calling the intrinsic contain + * the checks omitted by the intrinsic (if any).
    • + *
    • When modifying an existing intrinsic, the Java libraries must be updated + * to match the semantics of the intrinsic and to execute all checks omitted + * by the intrinsic (if any).
    • + *
    + * + * Persons not directly involved with maintaining the Java libraries or the + * HotSpot VM can safely ignore the fact that a method is annotated with + * {@code @HotSpotIntrinsicCandidate}. + * + * The HotSpot VM defines (internally) a list of intrinsics. Not all intrinsic + * are available on all platforms supported by the HotSpot VM. Furthermore, + * the availability of an intrinsic on a given platform depends on the + * configuration of the HotSpot VM (e.g., the set of VM flags enabled). + * Therefore, annotating a method with {@code @HotSpotIntrinsicCandidate} does + * not guarantee that the marked method is intrinsified by the HotSpot VM. + * + * If the {@code CheckIntrinsics} VM flag is enabled, the HotSpot VM checks + * (when loading a class) that (1) all methods of that class that are also on + * the VM's list of intrinsics are annotated with {@code @HotSpotIntrinsicCandidate} + * and that (2) for all methods of that class annotated with + * {@code @HotSpotIntrinsicCandidate} there is an intrinsic in the list. + * + * @since 1.9 + */ +@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotIntrinsicCandidate { +} diff --git a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java index 6d7078a9751..b6cca9d8f14 100644 --- a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java +++ b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java @@ -31,6 +31,8 @@ import java.security.ProtectionDomain; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; +import jdk.internal.HotSpotIntrinsicCandidate; + /** * A collection of methods for performing low-level, unsafe operations. @@ -148,6 +150,7 @@ public final class Unsafe { * @throws RuntimeException No defined exceptions are thrown, not even * {@link NullPointerException} */ + @HotSpotIntrinsicCandidate public native int getInt(Object o, long offset); /** @@ -170,12 +173,14 @@ public final class Unsafe { * @throws RuntimeException No defined exceptions are thrown, not even * {@link NullPointerException} */ + @HotSpotIntrinsicCandidate public native void putInt(Object o, long offset, int x); /** * Fetches a reference value from a given Java variable. * @see #getInt(Object, long) */ + @HotSpotIntrinsicCandidate public native Object getObject(Object o, long offset); /** @@ -188,35 +193,50 @@ public final class Unsafe { * are updated. * @see #putInt(Object, long, int) */ + @HotSpotIntrinsicCandidate public native void putObject(Object o, long offset, Object x); /** @see #getInt(Object, long) */ + @HotSpotIntrinsicCandidate public native boolean getBoolean(Object o, long offset); /** @see #putInt(Object, long, int) */ + @HotSpotIntrinsicCandidate public native void putBoolean(Object o, long offset, boolean x); /** @see #getInt(Object, long) */ + @HotSpotIntrinsicCandidate public native byte getByte(Object o, long offset); /** @see #putInt(Object, long, int) */ + @HotSpotIntrinsicCandidate public native void putByte(Object o, long offset, byte x); /** @see #getInt(Object, long) */ + @HotSpotIntrinsicCandidate public native short getShort(Object o, long offset); /** @see #putInt(Object, long, int) */ + @HotSpotIntrinsicCandidate public native void putShort(Object o, long offset, short x); /** @see #getInt(Object, long) */ + @HotSpotIntrinsicCandidate public native char getChar(Object o, long offset); /** @see #putInt(Object, long, int) */ + @HotSpotIntrinsicCandidate public native void putChar(Object o, long offset, char x); /** @see #getInt(Object, long) */ + @HotSpotIntrinsicCandidate public native long getLong(Object o, long offset); /** @see #putInt(Object, long, int) */ + @HotSpotIntrinsicCandidate public native void putLong(Object o, long offset, long x); /** @see #getInt(Object, long) */ + @HotSpotIntrinsicCandidate public native float getFloat(Object o, long offset); /** @see #putInt(Object, long, int) */ + @HotSpotIntrinsicCandidate public native void putFloat(Object o, long offset, float x); /** @see #getInt(Object, long) */ + @HotSpotIntrinsicCandidate public native double getDouble(Object o, long offset); /** @see #putInt(Object, long, int) */ + @HotSpotIntrinsicCandidate public native void putDouble(Object o, long offset, double x); // These read VM internal data. @@ -257,6 +277,7 @@ public final class Unsafe { * * @see #allocateMemory */ + @HotSpotIntrinsicCandidate public native byte getByte(long address); /** @@ -266,31 +287,44 @@ public final class Unsafe { * * @see #getByte(long) */ + @HotSpotIntrinsicCandidate public native void putByte(long address, byte x); /** @see #getByte(long) */ + @HotSpotIntrinsicCandidate public native short getShort(long address); /** @see #putByte(long, byte) */ + @HotSpotIntrinsicCandidate public native void putShort(long address, short x); /** @see #getByte(long) */ + @HotSpotIntrinsicCandidate public native char getChar(long address); /** @see #putByte(long, byte) */ + @HotSpotIntrinsicCandidate public native void putChar(long address, char x); /** @see #getByte(long) */ + @HotSpotIntrinsicCandidate public native int getInt(long address); /** @see #putByte(long, byte) */ + @HotSpotIntrinsicCandidate public native void putInt(long address, int x); /** @see #getByte(long) */ + @HotSpotIntrinsicCandidate public native long getLong(long address); /** @see #putByte(long, byte) */ + @HotSpotIntrinsicCandidate public native void putLong(long address, long x); /** @see #getByte(long) */ + @HotSpotIntrinsicCandidate public native float getFloat(long address); /** @see #putByte(long, byte) */ + @HotSpotIntrinsicCandidate public native void putFloat(long address, float x); /** @see #getByte(long) */ + @HotSpotIntrinsicCandidate public native double getDouble(long address); /** @see #putByte(long, byte) */ + @HotSpotIntrinsicCandidate public native void putDouble(long address, double x); /** @@ -307,6 +341,7 @@ public final class Unsafe { * * @see #allocateMemory */ + @HotSpotIntrinsicCandidate public native long getAddress(long address); /** @@ -319,6 +354,7 @@ public final class Unsafe { * * @see #getAddress(long) */ + @HotSpotIntrinsicCandidate public native void putAddress(long address, long x); /// wrappers for malloc, realloc, free: @@ -406,6 +442,7 @@ public final class Unsafe { * * @since 1.7 */ + @HotSpotIntrinsicCandidate public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); @@ -651,6 +688,7 @@ public final class Unsafe { * Allocates an instance but does not run any constructor. * Initializes the class if it has not yet been. */ + @HotSpotIntrinsicCandidate public native Object allocateInstance(Class cls) throws InstantiationException; @@ -666,6 +704,7 @@ public final class Unsafe { * * @return {@code true} if successful */ + @HotSpotIntrinsicCandidate public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); @@ -679,6 +718,7 @@ public final class Unsafe { * * @return {@code true} if successful */ + @HotSpotIntrinsicCandidate public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x); @@ -692,6 +732,7 @@ public final class Unsafe { * * @return {@code true} if successful */ + @HotSpotIntrinsicCandidate public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x); @@ -700,60 +741,78 @@ public final class Unsafe { * Fetches a reference value from a given Java variable, with volatile * load semantics. Otherwise identical to {@link #getObject(Object, long)} */ + @HotSpotIntrinsicCandidate public native Object getObjectVolatile(Object o, long offset); /** * Stores a reference value into a given Java variable, with * volatile store semantics. Otherwise identical to {@link #putObject(Object, long, Object)} */ + @HotSpotIntrinsicCandidate public native void putObjectVolatile(Object o, long offset, Object x); /** Volatile version of {@link #getInt(Object, long)} */ + @HotSpotIntrinsicCandidate public native int getIntVolatile(Object o, long offset); /** Volatile version of {@link #putInt(Object, long, int)} */ + @HotSpotIntrinsicCandidate public native void putIntVolatile(Object o, long offset, int x); /** Volatile version of {@link #getBoolean(Object, long)} */ + @HotSpotIntrinsicCandidate public native boolean getBooleanVolatile(Object o, long offset); /** Volatile version of {@link #putBoolean(Object, long, boolean)} */ + @HotSpotIntrinsicCandidate public native void putBooleanVolatile(Object o, long offset, boolean x); /** Volatile version of {@link #getByte(Object, long)} */ + @HotSpotIntrinsicCandidate public native byte getByteVolatile(Object o, long offset); /** Volatile version of {@link #putByte(Object, long, byte)} */ + @HotSpotIntrinsicCandidate public native void putByteVolatile(Object o, long offset, byte x); /** Volatile version of {@link #getShort(Object, long)} */ + @HotSpotIntrinsicCandidate public native short getShortVolatile(Object o, long offset); /** Volatile version of {@link #putShort(Object, long, short)} */ + @HotSpotIntrinsicCandidate public native void putShortVolatile(Object o, long offset, short x); /** Volatile version of {@link #getChar(Object, long)} */ + @HotSpotIntrinsicCandidate public native char getCharVolatile(Object o, long offset); /** Volatile version of {@link #putChar(Object, long, char)} */ + @HotSpotIntrinsicCandidate public native void putCharVolatile(Object o, long offset, char x); /** Volatile version of {@link #getLong(Object, long)} */ + @HotSpotIntrinsicCandidate public native long getLongVolatile(Object o, long offset); /** Volatile version of {@link #putLong(Object, long, long)} */ + @HotSpotIntrinsicCandidate public native void putLongVolatile(Object o, long offset, long x); /** Volatile version of {@link #getFloat(Object, long)} */ + @HotSpotIntrinsicCandidate public native float getFloatVolatile(Object o, long offset); /** Volatile version of {@link #putFloat(Object, long, float)} */ + @HotSpotIntrinsicCandidate public native void putFloatVolatile(Object o, long offset, float x); /** Volatile version of {@link #getDouble(Object, long)} */ + @HotSpotIntrinsicCandidate public native double getDoubleVolatile(Object o, long offset); /** Volatile version of {@link #putDouble(Object, long, double)} */ + @HotSpotIntrinsicCandidate public native void putDoubleVolatile(Object o, long offset, double x); /** @@ -765,12 +824,15 @@ public final class Unsafe { * * Corresponds to C11 atomic_store_explicit(..., memory_order_release). */ + @HotSpotIntrinsicCandidate public native void putOrderedObject(Object o, long offset, Object x); /** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */ + @HotSpotIntrinsicCandidate public native void putOrderedInt(Object o, long offset, int x); /** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)} */ + @HotSpotIntrinsicCandidate public native void putOrderedLong(Object o, long offset, long x); /** @@ -785,6 +847,7 @@ public final class Unsafe { * * @param thread the thread to unpark. */ + @HotSpotIntrinsicCandidate public native void unpark(Object thread); /** @@ -798,6 +861,7 @@ public final class Unsafe { * because {@code unpark} is, so it would be strange to place it * elsewhere. */ + @HotSpotIntrinsicCandidate public native void park(boolean isAbsolute, long time); /** @@ -831,6 +895,7 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ + @HotSpotIntrinsicCandidate public final int getAndAddInt(Object o, long offset, int delta) { int v; do { @@ -850,6 +915,7 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ + @HotSpotIntrinsicCandidate public final long getAndAddLong(Object o, long offset, long delta) { long v; do { @@ -869,6 +935,7 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ + @HotSpotIntrinsicCandidate public final int getAndSetInt(Object o, long offset, int newValue) { int v; do { @@ -888,6 +955,7 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ + @HotSpotIntrinsicCandidate public final long getAndSetLong(Object o, long offset, long newValue) { long v; do { @@ -907,6 +975,7 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ + @HotSpotIntrinsicCandidate public final Object getAndSetObject(Object o, long offset, Object newValue) { Object v; do { @@ -928,6 +997,7 @@ public final class Unsafe { * provide a LoadLoad barrier also provide a LoadStore barrier for free. * @since 1.8 */ + @HotSpotIntrinsicCandidate public native void loadFence(); /** @@ -942,6 +1012,7 @@ public final class Unsafe { * provide a StoreStore barrier also provide a LoadStore barrier for free. * @since 1.8 */ + @HotSpotIntrinsicCandidate public native void storeFence(); /** @@ -953,6 +1024,7 @@ public final class Unsafe { * Corresponds to C11 atomic_thread_fence(memory_order_seq_cst). * @since 1.8 */ + @HotSpotIntrinsicCandidate public native void fullFence(); /** @@ -1010,6 +1082,7 @@ public final class Unsafe { * {@link NullPointerException} * @since 1.9 */ + @HotSpotIntrinsicCandidate public final long getLongUnaligned(Object o, long offset) { if ((offset & 7) == 0) { return getLong(o, offset); @@ -1048,6 +1121,7 @@ public final class Unsafe { } /** @see #getLongUnaligned(Object, long) */ + @HotSpotIntrinsicCandidate public final int getIntUnaligned(Object o, long offset) { if ((offset & 3) == 0) { return getInt(o, offset); @@ -1067,6 +1141,7 @@ public final class Unsafe { } /** @see #getLongUnaligned(Object, long) */ + @HotSpotIntrinsicCandidate public final short getShortUnaligned(Object o, long offset) { if ((offset & 1) == 0) { return getShort(o, offset); @@ -1081,9 +1156,11 @@ public final class Unsafe { } /** @see #getLongUnaligned(Object, long) */ + @HotSpotIntrinsicCandidate public final char getCharUnaligned(Object o, long offset) { return (char)getShortUnaligned(o, offset); } + /** @see #getLongUnaligned(Object, long, boolean) */ public final char getCharUnaligned(Object o, long offset, boolean bigEndian) { return convEndian(bigEndian, getCharUnaligned(o, offset)); @@ -1117,6 +1194,7 @@ public final class Unsafe { * {@link NullPointerException} * @since 1.9 */ + @HotSpotIntrinsicCandidate public final void putLongUnaligned(Object o, long offset, long x) { if ((offset & 7) == 0) { putLong(o, offset, x); @@ -1142,6 +1220,7 @@ public final class Unsafe { (byte)(x >>> 56)); } } + /** * As {@link #putLongUnaligned(Object, long, long)} but with an additional * argument which specifies the endianness of the value as stored in memory. @@ -1158,6 +1237,7 @@ public final class Unsafe { } /** @see #putLongUnaligned(Object, long, long) */ + @HotSpotIntrinsicCandidate public final void putIntUnaligned(Object o, long offset, int x) { if ((offset & 3) == 0) { putInt(o, offset, x); @@ -1179,6 +1259,7 @@ public final class Unsafe { } /** @see #putLongUnaligned(Object, long, long) */ + @HotSpotIntrinsicCandidate public final void putShortUnaligned(Object o, long offset, short x) { if ((offset & 1) == 0) { putShort(o, offset, x); @@ -1194,6 +1275,7 @@ public final class Unsafe { } /** @see #putLongUnaligned(Object, long, long) */ + @HotSpotIntrinsicCandidate public final void putCharUnaligned(Object o, long offset, char x) { putShortUnaligned(o, offset, (short)x); } diff --git a/jdk/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java b/jdk/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java index 559f7e1cea8..30181337173 100644 --- a/jdk/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java +++ b/jdk/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java @@ -32,6 +32,9 @@ import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.util.Arrays; +import java.util.Objects; + +import jdk.internal.HotSpotIntrinsicCandidate; class ISO_8859_1 extends Charset @@ -147,9 +150,16 @@ class ISO_8859_1 private final Surrogate.Parser sgp = new Surrogate.Parser(); - // JVM may replace this method with intrinsic code. + // Method possible replaced with a compiler intrinsic. private static int encodeISOArray(char[] sa, int sp, - byte[] da, int dp, int len) + byte[] da, int dp, int len) { + encodeISOArrayCheck(sa, sp, da, dp, len); + return implEncodeISOArray(sa, sp, da, dp, len); + } + + @HotSpotIntrinsicCandidate + private static int implEncodeISOArray(char[] sa, int sp, + byte[] da, int dp, int len) { int i = 0; for (; i < len; i++) { @@ -161,6 +171,34 @@ class ISO_8859_1 return i; } + private static void encodeISOArrayCheck(char[] sa, int sp, + byte[] da, int dp, int len) { + if (len <= 0) { + return; // not an error because encodeISOArrayImpl won't execute if len <= 0 + } + + Objects.requireNonNull(sa); + Objects.requireNonNull(da); + + if (sp < 0 || sp >= sa.length) { + throw new ArrayIndexOutOfBoundsException(sp); + } + + if (dp < 0 || dp >= da.length) { + throw new ArrayIndexOutOfBoundsException(dp); + } + + int endIndexSP = sp + len - 1; + if (endIndexSP < 0 || endIndexSP >= sa.length) { + throw new ArrayIndexOutOfBoundsException(endIndexSP); + } + + int endIndexDP = dp + len - 1; + if (endIndexDP < 0 || endIndexDP >= da.length) { + throw new ArrayIndexOutOfBoundsException(endIndexDP); + } + } + private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { diff --git a/jdk/src/java.base/share/classes/sun/reflect/Reflection.java b/jdk/src/java.base/share/classes/sun/reflect/Reflection.java index bc3e13e23cb..c7c8ded287d 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/Reflection.java +++ b/jdk/src/java.base/share/classes/sun/reflect/Reflection.java @@ -28,6 +28,7 @@ package sun.reflect; import java.lang.reflect.*; import java.util.HashMap; import java.util.Map; +import jdk.internal.HotSpotIntrinsicCandidate; /** Common utility routines used by both java.lang and java.lang.reflect */ @@ -56,6 +57,7 @@ public class Reflection { ignoring frames associated with java.lang.reflect.Method.invoke() and its implementation. */ @CallerSensitive + @HotSpotIntrinsicCandidate public static native Class getCallerClass(); /** @@ -74,6 +76,7 @@ public class Reflection { to compatibility reasons; see 4471811. Only the values of the low 13 bits (i.e., a mask of 0x1FFF) are guaranteed to be valid. */ + @HotSpotIntrinsicCandidate public static native int getClassAccessFlags(Class c); /** A quick "fast-path" check to try to avoid getCallerClass() diff --git a/jdk/src/java.base/share/classes/sun/security/provider/DigestBase.java b/jdk/src/java.base/share/classes/sun/security/provider/DigestBase.java index 98af71afdf0..24847c0abf3 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/DigestBase.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/DigestBase.java @@ -28,6 +28,9 @@ package sun.security.provider; import java.security.MessageDigestSpi; import java.security.DigestException; import java.security.ProviderException; +import java.util.Objects; + +import jdk.internal.HotSpotIntrinsicCandidate; /** * Common base message digest implementation for the Sun provider. @@ -136,12 +139,36 @@ abstract class DigestBase extends MessageDigestSpi implements Cloneable { // compress complete blocks private int implCompressMultiBlock(byte[] b, int ofs, int limit) { + implCompressMultiBlockCheck(b, ofs, limit); + return implCompressMultiBlock0(b, ofs, limit); + } + + @HotSpotIntrinsicCandidate + private int implCompressMultiBlock0(byte[] b, int ofs, int limit) { for (; ofs <= limit; ofs += blockSize) { implCompress(b, ofs); } return ofs; } + private void implCompressMultiBlockCheck(byte[] b, int ofs, int limit) { + if (limit < 0) { + return; // not an error because implCompressMultiBlockImpl won't execute if limit < 0 + // and an exception is thrown if ofs < 0. + } + + Objects.requireNonNull(b); + + if (ofs < 0 || ofs >= b.length) { + throw new ArrayIndexOutOfBoundsException(ofs); + } + + int endIndex = (limit / blockSize) * blockSize + blockSize - 1; + if (endIndex >= b.length) { + throw new ArrayIndexOutOfBoundsException(endIndex); + } + } + // reset this object. See JCA doc. protected final void engineReset() { if (bytesProcessed == 0) { diff --git a/jdk/src/java.base/share/classes/sun/security/provider/SHA.java b/jdk/src/java.base/share/classes/sun/security/provider/SHA.java index 05a936bbd04..0fd334d8a22 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/SHA.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/SHA.java @@ -25,7 +25,10 @@ package sun.security.provider; +import java.util.Objects; + import static sun.security.provider.ByteArrayAccess.*; +import jdk.internal.HotSpotIntrinsicCandidate; /** * This class implements the Secure Hash Algorithm (SHA) developed by @@ -114,8 +117,27 @@ public final class SHA extends DigestBase { * "old" NIST Secure Hash Algorithm. */ void implCompress(byte[] buf, int ofs) { - b2iBig64(buf, ofs, W); + implCompressCheck(buf, ofs); + implCompress0(buf, ofs); + } + private void implCompressCheck(byte[] buf, int ofs) { + Objects.requireNonNull(buf); + + // The checks performed by the method 'b2iBig64' + // are sufficient for the case when the method + // 'implCompressImpl' is replaced with a compiler + // intrinsic. + b2iBig64(buf, ofs, W); + } + + // The method 'implCompressImpl seems not to use its parameters. + // The method can, however, be replaced with a compiler intrinsic + // that operates directly on the array 'buf' (starting from + // offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs' + // must be passed as parameter to the method. + @HotSpotIntrinsicCandidate + private void implCompress0(byte[] buf, int ofs) { // The first 16 ints have the byte stream, compute the rest of // the buffer for (int t = 16; t <= 79; t++) { diff --git a/jdk/src/java.base/share/classes/sun/security/provider/SHA2.java b/jdk/src/java.base/share/classes/sun/security/provider/SHA2.java index 23007c96527..4cadf569f9a 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/SHA2.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/SHA2.java @@ -25,6 +25,9 @@ package sun.security.provider; +import java.util.Objects; + +import jdk.internal.HotSpotIntrinsicCandidate; import static sun.security.provider.ByteArrayAccess.*; /** @@ -186,8 +189,27 @@ abstract class SHA2 extends DigestBase { * Process the current block to update the state variable state. */ void implCompress(byte[] buf, int ofs) { - b2iBig64(buf, ofs, W); + implCompressCheck(buf, ofs); + implCompress0(buf, ofs); + } + private void implCompressCheck(byte[] buf, int ofs) { + Objects.requireNonNull(buf); + + // The checks performed by the method 'b2iBig64' + // are sufficient for the case when the method + // 'implCompressImpl' is replaced with a compiler + // intrinsic. + b2iBig64(buf, ofs, W); + } + + // The method 'implCompressImpl' seems not to use its parameters. + // The method can, however, be replaced with a compiler intrinsic + // that operates directly on the array 'buf' (starting from + // offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs' + // must be passed as parameter to the method. + @HotSpotIntrinsicCandidate + private void implCompress0(byte[] buf, int ofs) { // The first 16 ints are from the byte stream, compute the rest of // the W[]'s for (int t = 16; t < ITERATION; t++) { diff --git a/jdk/src/java.base/share/classes/sun/security/provider/SHA5.java b/jdk/src/java.base/share/classes/sun/security/provider/SHA5.java index 4ba30372c00..73cfb3292de 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/SHA5.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/SHA5.java @@ -26,8 +26,10 @@ package sun.security.provider; import java.security.*; +import java.util.Objects; import java.math.BigInteger; +import jdk.internal.HotSpotIntrinsicCandidate; import static sun.security.provider.ByteArrayAccess.*; /** @@ -205,8 +207,27 @@ abstract class SHA5 extends DigestBase { * "old" NIST Secure Hash Algorithm. */ final void implCompress(byte[] buf, int ofs) { - b2lBig128(buf, ofs, W); + implCompressCheck(buf, ofs); + implCompress0(buf, ofs); + } + private void implCompressCheck(byte[] buf, int ofs) { + Objects.requireNonNull(buf); + + // The checks performed by the method 'b2iBig128' + // are sufficient for the case when the method + // 'implCompressImpl' is replaced with a compiler + // intrinsic. + b2lBig128(buf, ofs, W); + } + + // The method 'implCompressImpl' seems not to use its parameters. + // The method can, however, be replaced with a compiler intrinsic + // that operates directly on the array 'buf' (starting from + // offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs' + // must be passed as parameter to the method. + @HotSpotIntrinsicCandidate + private final void implCompress0(byte[] buf, int ofs) { // The first 16 longs are from the byte stream, compute the rest of // the W[]'s for (int t = 16; t < ITERATION; t++) { diff --git a/jdk/src/java.base/share/native/libzip/CRC32.c b/jdk/src/java.base/share/native/libzip/CRC32.c index b03b2b9c53c..5d1a5c34d95 100644 --- a/jdk/src/java.base/share/native/libzip/CRC32.c +++ b/jdk/src/java.base/share/native/libzip/CRC32.c @@ -43,8 +43,8 @@ Java_java_util_zip_CRC32_update(JNIEnv *env, jclass cls, jint crc, jint b) } JNIEXPORT jint JNICALL -Java_java_util_zip_CRC32_updateBytes(JNIEnv *env, jclass cls, jint crc, - jarray b, jint off, jint len) +Java_java_util_zip_CRC32_updateBytes0(JNIEnv *env, jclass cls, jint crc, + jarray b, jint off, jint len) { Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0); if (buf) { @@ -61,8 +61,8 @@ ZIP_CRC32(jint crc, const jbyte *buf, jint len) } JNIEXPORT jint JNICALL -Java_java_util_zip_CRC32_updateByteBuffer(JNIEnv *env, jclass cls, jint crc, - jlong address, jint off, jint len) +Java_java_util_zip_CRC32_updateByteBuffer0(JNIEnv *env, jclass cls, jint crc, + jlong address, jint off, jint len) { Bytef *buf = (Bytef *)jlong_to_ptr(address); if (buf) { From a26c73956ca134c348e0ce95d2c2aa656ca34034 Mon Sep 17 00:00:00 2001 From: Yuri Nesterenko Date: Fri, 3 Jul 2015 17:37:40 +0300 Subject: [PATCH 16/21] 8130125: [TEST_BUG] add @modules to the several client tests unaffected by the automated bulk update Reviewed-by: serb, alexsch --- .../awt/EventQueue/6980209/bug6980209.java | 11 +- .../awt/FileDialog/8017487/bug8017487.java | 1 + .../Focus/8073453/AWTFocusTransitionTest.java | 11 +- .../8073453/SwingFocusTransitionTest.java | 11 +- .../FocusEmbeddedFrameTest.java | 2 + .../NonEDT_GUI_Deadlock.html | 44 +++ .../NonEDT_GUI_Deadlock.java | 323 ++++++++++++++++++ jdk/test/java/awt/JAWT/JAWT.sh | 4 +- jdk/test/java/awt/JAWT/Makefile.unix | 2 +- .../JButtonInGlassPaneOverlapping.java | 1 + .../Mixing/AWT_Mixing/JButtonOverlapping.java | 1 + .../AWT_Mixing/JColorChooserOverlapping.java | 1 + .../AWT_Mixing/JComboBoxOverlapping.java | 1 + .../JEditorPaneInGlassPaneOverlapping.java | 1 + .../AWT_Mixing/JEditorPaneOverlapping.java | 1 + .../JGlassPaneInternalFrameOverlapping.java | 1 + .../AWT_Mixing/JGlassPaneMoveOverlapping.java | 1 + .../JInternalFrameMoveOverlapping.java | 1 + .../AWT_Mixing/JInternalFrameOverlapping.java | 1 + .../JLabelInGlassPaneOverlapping.java | 1 + .../Mixing/AWT_Mixing/JLabelOverlapping.java | 1 + .../JListInGlassPaneOverlapping.java | 1 + .../Mixing/AWT_Mixing/JListOverlapping.java | 1 + .../AWT_Mixing/JMenuBarOverlapping.java | 1 + .../JPanelInGlassPaneOverlapping.java | 1 + .../Mixing/AWT_Mixing/JPanelOverlapping.java | 1 + .../AWT_Mixing/JPopupMenuOverlapping.java | 1 + .../JProgressBarInGlassPaneOverlapping.java | 1 + .../AWT_Mixing/JProgressBarOverlapping.java | 1 + .../JScrollBarInGlassPaneOverlapping.java | 1 + .../AWT_Mixing/JScrollBarOverlapping.java | 1 + .../AWT_Mixing/JScrollPaneOverlapping.java | 1 + .../JSliderInGlassPaneOverlapping.java | 1 + .../Mixing/AWT_Mixing/JSliderOverlapping.java | 1 + .../JSpinnerInGlassPaneOverlapping.java | 1 + .../AWT_Mixing/JSpinnerOverlapping.java | 1 + .../AWT_Mixing/JSplitPaneOverlapping.java | 4 +- .../JTableInGlassPaneOverlapping.java | 1 + .../Mixing/AWT_Mixing/JTableOverlapping.java | 1 + .../JTextAreaInGlassPaneOverlapping.java | 1 + .../AWT_Mixing/JTextAreaOverlapping.java | 1 + .../JTextFieldInGlassPaneOverlapping.java | 1 + .../AWT_Mixing/JTextFieldOverlapping.java | 1 + .../JToggleButtonInGlassPaneOverlapping.java | 1 + .../AWT_Mixing/JToggleButtonOverlapping.java | 1 + .../AWT_Mixing/MixingFrameResizing.java | 1 + .../Mixing/AWT_Mixing/OpaqueOverlapping.java | 1 + .../AWT_Mixing/OpaqueOverlappingChoice.java | 1 + .../AWT_Mixing/ViewportOverlapping.java | 1 + .../bug7129742.java | 2 + .../MultiResolutionDragImageTest.java | 4 +- .../awt/font/GlyphVector/TestLayoutFlags.java | 209 ++++++++++++ .../awt/font/Underline/UnderlineTest.java | 160 +++++++++ .../EmbeddedFrameTest1.java | 2 + .../awt/xembed/server/TestXEmbedServer.java | 5 +- .../JFileChooser/8080628/bug8080628.java | 1 + .../RepaintManager/6608456/bug6608456.java | 1 + .../DisplayListenerLeak.java | 3 +- .../TestSGEuseAlternateFontforJALocales.java | 1 + 59 files changed, 813 insertions(+), 27 deletions(-) create mode 100644 jdk/test/java/awt/Frame/NonEDT_GUI_DeadlockTest/NonEDT_GUI_Deadlock.html create mode 100644 jdk/test/java/awt/Frame/NonEDT_GUI_DeadlockTest/NonEDT_GUI_Deadlock.java create mode 100644 jdk/test/java/awt/font/GlyphVector/TestLayoutFlags.java create mode 100644 jdk/test/java/awt/font/Underline/UnderlineTest.java diff --git a/jdk/test/java/awt/EventQueue/6980209/bug6980209.java b/jdk/test/java/awt/EventQueue/6980209/bug6980209.java index d39235ae44c..0f1080cba02 100644 --- a/jdk/test/java/awt/EventQueue/6980209/bug6980209.java +++ b/jdk/test/java/awt/EventQueue/6980209/bug6980209.java @@ -27,18 +27,17 @@ @author Semyon Sadetsky */ -import sun.util.logging.PlatformLogger; - import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; +import java.util.logging.Logger; public class bug6980209 implements ActionListener { - private final static PlatformLogger log = - PlatformLogger.getLogger("java.awt.event.WaitDispatchSupport"); + private final static Logger log = + Logger.getLogger("java.awt.event.WaitDispatchSupport"); public static final int ATTEMPTS = 100; public static final int EVENTS = 5; @@ -52,8 +51,8 @@ public class bug6980209 implements ActionListener { public static void main(String[] args) throws Exception { System.out.println( "PLEASE DO NOT TOUCH KEYBOARD AND MOUSE DURING THE TEST RUN!"); - // log.setLevel(PlatformLogger.Level.FINE); - // log.setLevel(PlatformLogger.Level.FINEST); + // log.setLevel(java.util.logging.Level.FINE); + // log.setLevel(java.util.logging.Level.FINEST); try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { diff --git a/jdk/test/java/awt/FileDialog/8017487/bug8017487.java b/jdk/test/java/awt/FileDialog/8017487/bug8017487.java index c9cd370e10a..f3c3fbcc025 100644 --- a/jdk/test/java/awt/FileDialog/8017487/bug8017487.java +++ b/jdk/test/java/awt/FileDialog/8017487/bug8017487.java @@ -25,6 +25,7 @@ @bug 8017487 @summary filechooser in Windows-Libraries folder: columns are mixed up @author Semyon Sadetsky + @modules java.desktop/sun.awt.shell @library /lib/testlibrary @build jdk.testlibrary.OSInfo @run main bug8017487 diff --git a/jdk/test/java/awt/Focus/8073453/AWTFocusTransitionTest.java b/jdk/test/java/awt/Focus/8073453/AWTFocusTransitionTest.java index e4230b1fd26..7acf7f5dfc7 100644 --- a/jdk/test/java/awt/Focus/8073453/AWTFocusTransitionTest.java +++ b/jdk/test/java/awt/Focus/8073453/AWTFocusTransitionTest.java @@ -28,13 +28,11 @@ * @compile AWTFocusTransitionTest.java * @run main/othervm AWTFocusTransitionTest */ -import sun.awt.SunToolkit; import java.awt.*; import java.awt.event.KeyEvent; public class AWTFocusTransitionTest { - private static SunToolkit toolkit; private static Robot robot; private static Frame frame; @@ -42,20 +40,19 @@ public class AWTFocusTransitionTest { private static Button button; public static void main(String[] args) throws Exception { - toolkit = (SunToolkit)Toolkit.getDefaultToolkit(); robot = new Robot(); robot.setAutoDelay(50); try { createAndShowGUI(); - toolkit.realSync(); + robot.waitForIdle(); checkFocusOwner(textField); robot.keyPress(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_TAB); - toolkit.realSync(); + robot.waitForIdle(); checkFocusOwner(button); @@ -63,7 +60,7 @@ public class AWTFocusTransitionTest { robot.keyPress(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_SHIFT); - toolkit.realSync(); + robot.waitForIdle(); checkFocusOwner(textField); @@ -71,7 +68,7 @@ public class AWTFocusTransitionTest { robot.keyPress(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_SHIFT); - toolkit.realSync(); + robot.waitForIdle(); checkFocusOwner(button); } finally { diff --git a/jdk/test/java/awt/Focus/8073453/SwingFocusTransitionTest.java b/jdk/test/java/awt/Focus/8073453/SwingFocusTransitionTest.java index ec15cd392a7..c9947cca3c5 100644 --- a/jdk/test/java/awt/Focus/8073453/SwingFocusTransitionTest.java +++ b/jdk/test/java/awt/Focus/8073453/SwingFocusTransitionTest.java @@ -28,14 +28,12 @@ * @compile SwingFocusTransitionTest.java * @run main/othervm SwingFocusTransitionTest */ -import sun.awt.SunToolkit; import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; public class SwingFocusTransitionTest { - private static SunToolkit toolkit; private static Robot robot; private static JFrame frame; @@ -43,7 +41,6 @@ public class SwingFocusTransitionTest { private static JButton button; public static void main(String[] args) throws Exception { - toolkit = (SunToolkit)Toolkit.getDefaultToolkit(); robot = new Robot(); robot.setAutoDelay(50); @@ -55,13 +52,13 @@ public class SwingFocusTransitionTest { } }); - toolkit.realSync(); + robot.waitForIdle(); checkFocusOwner(textField); robot.keyPress(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_TAB); - toolkit.realSync(); + robot.waitForIdle(); checkFocusOwner(button); @@ -69,7 +66,7 @@ public class SwingFocusTransitionTest { robot.keyPress(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_SHIFT); - toolkit.realSync(); + robot.waitForIdle(); checkFocusOwner(textField); @@ -77,7 +74,7 @@ public class SwingFocusTransitionTest { robot.keyPress(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_SHIFT); - toolkit.realSync(); + robot.waitForIdle(); checkFocusOwner(button); } finally { diff --git a/jdk/test/java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java b/jdk/test/java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java index 999d9ac3320..763f01cda49 100644 --- a/jdk/test/java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java +++ b/jdk/test/java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java @@ -26,6 +26,8 @@ @bug 6516675 @summary Tests that EmbeddedFrame can be focused. @author anton.tarasov: area=awt-focus + @modules java.desktop/java.awt.peer + java.desktop/sun.awt @library ../../regtesthelpers @build Util UtilInternal @run main FocusEmbeddedFrameTest diff --git a/jdk/test/java/awt/Frame/NonEDT_GUI_DeadlockTest/NonEDT_GUI_Deadlock.html b/jdk/test/java/awt/Frame/NonEDT_GUI_DeadlockTest/NonEDT_GUI_Deadlock.html new file mode 100644 index 00000000000..b0bc28d78ad --- /dev/null +++ b/jdk/test/java/awt/Frame/NonEDT_GUI_DeadlockTest/NonEDT_GUI_Deadlock.html @@ -0,0 +1,44 @@ + + + + + + + + + +

    NonEDT_GUI_Deadlock
    Bug ID: 4828019

    + +

    This is an AUTOMATIC test, simply wait for completion

    + + + + + diff --git a/jdk/test/java/awt/Frame/NonEDT_GUI_DeadlockTest/NonEDT_GUI_Deadlock.java b/jdk/test/java/awt/Frame/NonEDT_GUI_DeadlockTest/NonEDT_GUI_Deadlock.java new file mode 100644 index 00000000000..41e7070b3d8 --- /dev/null +++ b/jdk/test/java/awt/Frame/NonEDT_GUI_DeadlockTest/NonEDT_GUI_Deadlock.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + test + @bug 4828019 + @summary Frame/Window deadlock + @author yan@sparc.spb.su: area= + @run applet NonEDT_GUI_Deadlock.html +*/ + +// Note there is no @ in front of test above. This is so that the +// harness will not mistake this file as a test file. It should +// only see the html file as a test file. (the harness runs all +// valid test files, so it would run this test twice if this file +// were valid as well as the html file.) +// Also, note the area= after Your Name in the author tag. Here, you +// should put which functional area the test falls in. See the +// AWT-core home page -> test areas and/or -> AWT team for a list of +// areas. +// Note also the 'AutomaticAppletTest.html' in the run tag. This should +// be changed to the name of the test. + + +/** + * NonEDT_GUI_Deadlock.java + * + * summary: + */ + +import java.applet.Applet; +import java.awt.*; +import java.awt.event.*; +import java.net.*; +import java.io.*; + + +//Automated tests should run as applet tests if possible because they +// get their environments cleaned up, including AWT threads, any +// test created threads, and any system resources used by the test +// such as file descriptors. (This is normally not a problem as +// main tests usually run in a separate VM, however on some platforms +// such as the Mac, separate VMs are not possible and non-applet +// tests will cause problems). Also, you don't have to worry about +// synchronisation stuff in Applet tests they way you do in main +// tests... + + +public class NonEDT_GUI_Deadlock extends Applet +{ + //Declare things used in the test, like buttons and labels here + boolean bOK = false; + Thread badThread = null; + + public void init() + { + //Create instructions for the user here, as well as set up + // the environment -- set the layout manager, add buttons, + // etc. + + + String[] instructions = + { + "This is an AUTOMATIC test", + "simply wait until it is done" + }; + Sysout.createDialog( ); + Sysout.printInstructions( instructions ); + + }//End init() + + public void start () + { + //Get things going. Request focus, set size, et cetera + + setSize (200,300); + setVisible(true); + validate(); + + final Frame theFrame = new Frame("Window test"); + theFrame.setSize(240, 200); + + Thread thKiller = new Thread() { + public void run() { + try { + Thread.sleep( 9000 ); + }catch( Exception ex ) { + } + if( !bOK ) { + // oops, + //Sysout.println("Deadlock!"); + Runtime.getRuntime().halt(0); + }else{ + //Sysout.println("Passed ok."); + } + } + }; + thKiller.setName("Killer thread"); + thKiller.start(); + Window w = new TestWindow(theFrame); + theFrame.toBack(); + theFrame.setVisible(true); + + theFrame.setLayout(new FlowLayout(FlowLayout.CENTER)); + EventQueue.invokeLater(new Runnable() { + public void run() { + bOK = true; + } + }); + + + + }// start() + class TestWindow extends Window implements Runnable { + + TestWindow(Frame f) { + super(f); + + //setSize(240, 75); + setLocation(0, 75); + + show(); + toFront(); + + badThread = new Thread(this); + badThread.setName("Bad Thread"); + badThread.start(); + + } + + public void paint(Graphics g) { + g.drawString("Deadlock or no deadlock?",20,80); + } + + public void run() { + + long ts = System.currentTimeMillis(); + + while (true) { + if ((System.currentTimeMillis()-ts)>3000) { + this.setVisible( false ); + dispose(); + break; + } + + toFront(); + try { + Thread.sleep(80); + } catch (Exception e) { + } + } + } + } + + + + public static void main(String args[]) { + NonEDT_GUI_Deadlock imt = new NonEDT_GUI_Deadlock(); + imt.init(); + imt.start(); + } + + +}// class NonEDT_GUI_Deadlock + + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout +{ + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn ); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog +{ + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + pack(); + + show(); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + System.out.println(messageIn); + } + +}// TestDialog class diff --git a/jdk/test/java/awt/JAWT/JAWT.sh b/jdk/test/java/awt/JAWT/JAWT.sh index 42107990fab..ab511d8a71e 100644 --- a/jdk/test/java/awt/JAWT/JAWT.sh +++ b/jdk/test/java/awt/JAWT/JAWT.sh @@ -129,7 +129,7 @@ case `uname -m` in esac echo "OS-ARCH is" ${SYST}-${ARCH} -${TESTJAVA}${FS}jre${FS}bin${FS}java -fullversion 2>&1 +${TESTJAVA}${FS}bin${FS}java -fullversion 2>&1 which ${MAKE} >${NULL} 2>&1 if [ "$?" -ne '0' ] @@ -156,7 +156,7 @@ esac cp ${TESTSRC}${FS}${MAKEFILE} . -JAVA=${TESTJAVA}${FS}jre${FS}bin${FS}java +JAVA=${TESTJAVA}${FS}bin${FS}java JAVAC=${TESTJAVA}${FS}bin${FS}javac JAVAH=${TESTJAVA}${FS}bin${FS}javah diff --git a/jdk/test/java/awt/JAWT/Makefile.unix b/jdk/test/java/awt/JAWT/Makefile.unix index f6a408f7720..b3be2f9a624 100644 --- a/jdk/test/java/awt/JAWT/Makefile.unix +++ b/jdk/test/java/awt/JAWT/Makefile.unix @@ -32,7 +32,7 @@ LINK = ld J_INC = $(TESTJAVA)/include INCLUDES = -I$(J_INC) -I$(J_INC)/$(SYST) -I. -LIBS = -L$(TESTJAVA)/jre/lib/$(ARCH) -ljawt -lX11 +LIBS = -L$(TESTJAVA)/lib/$(ARCH) -ljawt -lX11 all: $(CLASSES) libmylib.so diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JButtonInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JButtonInGlassPaneOverlapping.java index e39dbae5f6b..4cba54835e0 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JButtonInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JButtonInGlassPaneOverlapping.java @@ -34,6 +34,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JButtonInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JButtonOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JButtonOverlapping.java index 55bfb377c77..9120b7de785 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JButtonOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JButtonOverlapping.java @@ -34,6 +34,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JButtonOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JColorChooserOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JColorChooserOverlapping.java index d685ab8a858..61097379f9e 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JColorChooserOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JColorChooserOverlapping.java @@ -33,6 +33,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JColorChooserOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java index 6c4df6ae2ee..23ac96d3d77 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java @@ -44,6 +44,7 @@ import test.java.awt.regtesthelpers.Util; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JComboBoxOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JEditorPaneInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JEditorPaneInGlassPaneOverlapping.java index 9586e0dc1d2..7ac72debf3c 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JEditorPaneInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JEditorPaneInGlassPaneOverlapping.java @@ -35,6 +35,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JEditorPaneInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JEditorPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JEditorPaneOverlapping.java index 066528c75d8..22ef5bee0fb 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JEditorPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JEditorPaneOverlapping.java @@ -33,6 +33,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JEditorPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JGlassPaneInternalFrameOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JGlassPaneInternalFrameOverlapping.java index a042120ed21..93868816ced 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JGlassPaneInternalFrameOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JGlassPaneInternalFrameOverlapping.java @@ -46,6 +46,7 @@ import test.java.awt.regtesthelpers.Util; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JGlassPaneInternalFrameOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JGlassPaneMoveOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JGlassPaneMoveOverlapping.java index c5611db104e..d4596f2f728 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JGlassPaneMoveOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JGlassPaneMoveOverlapping.java @@ -47,6 +47,7 @@ import test.java.awt.regtesthelpers.Util; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JGlassPaneMoveOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JInternalFrameMoveOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JInternalFrameMoveOverlapping.java index 6b18cb57d41..c7fb1665b85 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JInternalFrameMoveOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JInternalFrameMoveOverlapping.java @@ -43,6 +43,7 @@ import test.java.awt.regtesthelpers.Util; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JInternalFrameMoveOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JInternalFrameOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JInternalFrameOverlapping.java index 845b7cd0f89..16dc79a2d44 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JInternalFrameOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JInternalFrameOverlapping.java @@ -42,6 +42,7 @@ import test.java.awt.regtesthelpers.Util; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JInternalFrameOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JLabelInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JLabelInGlassPaneOverlapping.java index d9b442e7523..4b34b71dee1 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JLabelInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JLabelInGlassPaneOverlapping.java @@ -35,6 +35,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JLabelInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JLabelOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JLabelOverlapping.java index 8871b85ccd8..dd89f63cd7d 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JLabelOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JLabelOverlapping.java @@ -34,6 +34,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JLabelOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JListInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JListInGlassPaneOverlapping.java index 69d9e4e06d9..4a087f9c6c5 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JListInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JListInGlassPaneOverlapping.java @@ -34,6 +34,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JListInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JListOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JListOverlapping.java index e17ede99764..77725e5b0e9 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JListOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JListOverlapping.java @@ -33,6 +33,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JListOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java index eb5501a6140..068d4f8b0ef 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java @@ -49,6 +49,7 @@ import test.java.awt.regtesthelpers.Util; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JMenuBarOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JPanelInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JPanelInGlassPaneOverlapping.java index ca57e4b6732..eb05250b7d1 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JPanelInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JPanelInGlassPaneOverlapping.java @@ -35,6 +35,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JPanelInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JPanelOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JPanelOverlapping.java index 2fb63331c7b..29a0e83d75a 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JPanelOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JPanelOverlapping.java @@ -34,6 +34,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JPanelOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java index 1bc2119b186..e635d8e335b 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java @@ -46,6 +46,7 @@ import test.java.awt.regtesthelpers.Util; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JPopupMenuOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JProgressBarInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JProgressBarInGlassPaneOverlapping.java index ca06e8e2671..5b806821be3 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JProgressBarInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JProgressBarInGlassPaneOverlapping.java @@ -35,6 +35,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JProgressBarInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JProgressBarOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JProgressBarOverlapping.java index 749ad80fa8b..bad98470dd8 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JProgressBarOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JProgressBarOverlapping.java @@ -34,6 +34,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JProgressBarOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollBarInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollBarInGlassPaneOverlapping.java index c8dcb9ec03e..06b66a577df 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollBarInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollBarInGlassPaneOverlapping.java @@ -38,6 +38,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JScrollBarInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollBarOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollBarOverlapping.java index c825dc88342..c439b6d0b02 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollBarOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollBarOverlapping.java @@ -37,6 +37,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JScrollBarOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollPaneOverlapping.java index a99fab91cec..929b6a58775 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JScrollPaneOverlapping.java @@ -44,6 +44,7 @@ import test.java.awt.regtesthelpers.Util; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JScrollPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JSliderInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JSliderInGlassPaneOverlapping.java index 350ec1a3d0b..463b9a7493e 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JSliderInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JSliderInGlassPaneOverlapping.java @@ -35,6 +35,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JSliderInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JSliderOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JSliderOverlapping.java index 39d6a1b7aa2..49f6d06a364 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JSliderOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JSliderOverlapping.java @@ -34,6 +34,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JSliderOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JSpinnerInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JSpinnerInGlassPaneOverlapping.java index c56f5834450..f41b7e19cf2 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JSpinnerInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JSpinnerInGlassPaneOverlapping.java @@ -37,6 +37,7 @@ import javax.swing.event.ChangeListener; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JSpinnerInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JSpinnerOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JSpinnerOverlapping.java index 2b0d5907df4..b9624d6bc15 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JSpinnerOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JSpinnerOverlapping.java @@ -36,6 +36,7 @@ import javax.swing.event.ChangeListener; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JSpinnerOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java index e4f9bcdbbae..a5edd005560 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java @@ -40,7 +40,8 @@ import test.java.awt.regtesthelpers.Util; /** * AWT/Swing overlapping test for {@link javax.swing.JSplitPane } component. - *

    This test creates puts heavyweight and lightweight components into different panels and test if splitter image and components itself are drawn correctly. + *

    This test puts heavyweight and lightweight components into different + * panels and test if splitter image and components itself are drawn correctly. *

    See base class for test info. */ /* @@ -50,6 +51,7 @@ import test.java.awt.regtesthelpers.Util; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JSplitPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java index 28249979c59..efe36b25de4 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java @@ -37,6 +37,7 @@ import javax.swing.event.TableModelListener; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JTableInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JTableOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JTableOverlapping.java index e118c59d6f2..0b184edd09a 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JTableOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JTableOverlapping.java @@ -33,6 +33,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JTableOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JTextAreaInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JTextAreaInGlassPaneOverlapping.java index 6d22b328b88..3f9ee35cbd2 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JTextAreaInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JTextAreaInGlassPaneOverlapping.java @@ -35,6 +35,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JTextAreaInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JTextAreaOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JTextAreaOverlapping.java index dcc87576a00..5ebfb8fef5d 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JTextAreaOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JTextAreaOverlapping.java @@ -34,6 +34,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JTextAreaOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JTextFieldInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JTextFieldInGlassPaneOverlapping.java index e73889b06ed..0ca69cc9ac7 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JTextFieldInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JTextFieldInGlassPaneOverlapping.java @@ -35,6 +35,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JTextFieldInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JTextFieldOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JTextFieldOverlapping.java index 75a979dcb1b..4c70b0c65ed 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JTextFieldOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JTextFieldOverlapping.java @@ -34,6 +34,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JTextFieldOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java index 5c7ede29dc5..cb10f6200b4 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java @@ -34,6 +34,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JToggleButtonInGlassPaneOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java index 6699bd5e889..8ac394a138d 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java @@ -33,6 +33,7 @@ import javax.swing.*; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main JToggleButtonOverlapping */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/MixingFrameResizing.java b/jdk/test/java/awt/Mixing/AWT_Mixing/MixingFrameResizing.java index ab18e1bb877..09ee233421c 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/MixingFrameResizing.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/MixingFrameResizing.java @@ -43,6 +43,7 @@ import test.java.awt.regtesthelpers.Util; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main MixingFrameResizing */ diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java index eb6701345bc..bed5517fba4 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java @@ -47,6 +47,7 @@ import test.java.awt.regtesthelpers.Util; @summary Opaque overlapping test for each AWT component @library ../../regtesthelpers @modules java.desktop/com.sun.awt + java.desktop/java.awt.peer java.desktop/sun.awt @build Util @run main OpaqueOverlapping diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/OpaqueOverlappingChoice.java b/jdk/test/java/awt/Mixing/AWT_Mixing/OpaqueOverlappingChoice.java index f92f36d4b49..9aceaed5d49 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/OpaqueOverlappingChoice.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/OpaqueOverlappingChoice.java @@ -33,6 +33,7 @@ @summary Opaque overlapping test for Choice AWT component @library ../../regtesthelpers @modules java.desktop/com.sun.awt + java.desktop/java.awt.peer java.desktop/sun.awt @build Util @run main OpaqueOverlappingChoice diff --git a/jdk/test/java/awt/Mixing/AWT_Mixing/ViewportOverlapping.java b/jdk/test/java/awt/Mixing/AWT_Mixing/ViewportOverlapping.java index 3b90c55ab11..2cfb251a6af 100644 --- a/jdk/test/java/awt/Mixing/AWT_Mixing/ViewportOverlapping.java +++ b/jdk/test/java/awt/Mixing/AWT_Mixing/ViewportOverlapping.java @@ -52,6 +52,7 @@ import test.java.awt.regtesthelpers.Util; @author sergey.grinev@oracle.com: area=awt.mixing @library ../../regtesthelpers @modules java.desktop/sun.awt + java.desktop/java.awt.peer @build Util @run main ViewportOverlapping */ diff --git a/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java b/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java index cfa609896fc..577544d53b5 100644 --- a/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java +++ b/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java @@ -29,6 +29,8 @@ /* @test * @bug 7129742 * @summary Focus in non-editable TextArea is not shown on Linux. + * @modules java.desktop/sun.awt + * java.desktop/java.awt.peer * @author Sean Chou */ diff --git a/jdk/test/java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java b/jdk/test/java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java index bde632c70cf..bb24972c7d0 100644 --- a/jdk/test/java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java +++ b/jdk/test/java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java @@ -36,6 +36,8 @@ import static java.awt.event.InputEvent.BUTTON1_DOWN_MASK; * @author Hendrik Schreiber * @summary [macosx] Drag image of TransferHandler does not honor * MultiResolutionImage + * @modules java.desktop/sun.awt.image + * java.desktop/sun.java2d * @run main MultiResolutionDragImageTest TEST_DRAG */ public class MultiResolutionDragImageTest { @@ -169,4 +171,4 @@ public class MultiResolutionDragImageTest { graphics.dispose(); return image; } -} \ No newline at end of file +} diff --git a/jdk/test/java/awt/font/GlyphVector/TestLayoutFlags.java b/jdk/test/java/awt/font/GlyphVector/TestLayoutFlags.java new file mode 100644 index 00000000000..f5111b2daf6 --- /dev/null +++ b/jdk/test/java/awt/font/GlyphVector/TestLayoutFlags.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* @test + @bug 4328745 5090704 + @summary exercise getLayoutFlags, getGlyphCharIndex, getGlyphCharIndices + */ + +import java.awt.*; +import java.awt.event.*; +import java.awt.font.*; +import java.awt.geom.*; + +public class TestLayoutFlags { + + static public void main(String[] args) { + new TestLayoutFlags().runTest(); + } + + void runTest() { + + Font font = new Font("Lucida Sans", Font.PLAIN, 24); + + String latin1 = "This is a latin1 string"; // none + String hebrew = "\u05d0\u05d1\u05d2\u05d3"; // rtl + String arabic = "\u0646\u0644\u0622\u0646"; // rtl + mc/g + String hindi = "\u0939\u093f\u0923\u094d\u0921\u0940"; // ltr + reorder + // String tamil = "\u0b9c\u0bcb"; // ltr + mg/c + split + + FontRenderContext frc = new FontRenderContext(null, true, true); + + // get glyph char indices needs to initializes layoutFlags before use (5090704) + { + GlyphVector gv = font.createGlyphVector(frc, "abcde"); + int ix = gv.getGlyphCharIndex(0); + if (ix != 0) { + throw new Error("glyph 0 incorrectly mapped to char " + ix); + } + int[] ixs = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); + for (int i = 0; i < ixs.length; ++i) { + if (ixs[i] != i) { + throw new Error("glyph " + i + " incorrectly mapped to char " + ixs[i]); + } + } + } + + GlyphVector latinGV = makeGlyphVector("Lucida Sans", frc, latin1, false, 1 /* ScriptRun.LATIN */); + GlyphVector hebrewGV = makeGlyphVector("Lucida Sans", frc, hebrew, true, 5 /* ScriptRun.HEBREW */); + GlyphVector arabicGV = makeGlyphVector("Lucida Sans", frc, arabic, true, 6 /* ScriptRun.ARABIC */); + GlyphVector hindiGV = makeGlyphVector("Lucida Sans", frc, hindi, false, 7 /* ScriptRun.DEVANAGARI */); + // GlyphVector tamilGV = makeGlyphVector("Devanagari MT for IBM", frc, tamil, false, 12 /* ScriptRun.TAMIL */); + + GlyphVector latinPos = font.createGlyphVector(frc, latin1); + Point2D pt = latinPos.getGlyphPosition(0); + pt.setLocation(pt.getX(), pt.getY() + 1.0); + latinPos.setGlyphPosition(0, pt); + + GlyphVector latinTrans = font.createGlyphVector(frc, latin1); + latinTrans.setGlyphTransform(0, AffineTransform.getRotateInstance(.15)); + + test("latin", latinGV, GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); + test("hebrew", hebrewGV, GlyphVector.FLAG_RUN_RTL | + GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); + test("arabic", arabicGV, GlyphVector.FLAG_RUN_RTL | + GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); + test("hindi", hindiGV, GlyphVector.FLAG_COMPLEX_GLYPHS | + GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); + // test("tamil", tamilGV, GlyphVector.FLAG_COMPLEX_GLYPHS); + test("pos", latinPos, GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); + test("trans", latinTrans, GlyphVector.FLAG_HAS_TRANSFORMS); + } + + GlyphVector makeGlyphVector(String fontname, FontRenderContext frc, String text, boolean rtl, int script) { + Font font = new Font(fontname, Font.PLAIN, 14); + System.out.println("asking for " + fontname + " and got " + font.getFontName()); + int flags = rtl ? 1 : 0; + return font.layoutGlyphVector(frc, text.toCharArray(), 0, text.length(), flags); + } + + void test(String name, GlyphVector gv, int expectedFlags) { + expectedFlags &= gv.FLAG_MASK; + int computedFlags = computeFlags(gv) & gv.FLAG_MASK; + int actualFlags = gv.getLayoutFlags() & gv.FLAG_MASK; + + System.out.println("\n*** " + name + " ***"); + System.out.println(" test flags"); + System.out.print("expected "); + printFlags(expectedFlags); + System.out.print("computed "); + printFlags(computedFlags); + System.out.print(" actual "); + printFlags(actualFlags); + + if (expectedFlags != actualFlags) { + throw new Error("layout flags in test: " + name + + " expected: " + Integer.toHexString(expectedFlags) + + " but got: " + Integer.toHexString(actualFlags)); + } + } + + static public void printFlags(int flags) { + System.out.print("flags:"); + if ((flags & GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS) != 0) { + System.out.print(" pos"); + } + if ((flags & GlyphVector.FLAG_HAS_TRANSFORMS) != 0) { + System.out.print(" trans"); + } + if ((flags & GlyphVector.FLAG_RUN_RTL) != 0) { + System.out.print(" rtl"); + } + if ((flags & GlyphVector.FLAG_COMPLEX_GLYPHS) != 0) { + System.out.print(" complex"); + } + if ((flags & GlyphVector.FLAG_MASK) == 0) { + System.out.print(" none"); + } + System.out.println(); + } + + int computeFlags(GlyphVector gv) { + validateCharIndexMethods(gv); + + int result = 0; + if (glyphsAreRTL(gv)) { + result |= GlyphVector.FLAG_RUN_RTL; + } + if (hasComplexGlyphs(gv)) { + result |= GlyphVector.FLAG_COMPLEX_GLYPHS; + } + + return result; + } + + /** + * throw an exception if getGlyphCharIndices returns a different result than + * you get from iterating through getGlyphCharIndex one at a time. + */ + void validateCharIndexMethods(GlyphVector gv) { + int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); + for (int i = 0; i < gv.getNumGlyphs(); ++i) { + if (gv.getGlyphCharIndex(i) != indices[i]) { + throw new Error("glyph index mismatch at " + i); + } + } + } + + /** + * Return true if the glyph indices are pure ltr + */ + boolean glyphsAreLTR(GlyphVector gv) { + int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); + for (int i = 0; i < indices.length; ++i) { + if (indices[i] != i) { + return false; + } + } + return true; + } + + /** + * Return true if the glyph indices are pure rtl + */ + boolean glyphsAreRTL(GlyphVector gv) { + int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); + for (int i = 0; i < indices.length; ++i) { + if (indices[i] != indices.length - i - 1) { + return false; + } + } + return true; + } + + /** + * Return true if there is a local reordering (the run is not ltr or rtl). + * !!! We can't have mixed bidi runs in the glyphs. + */ + boolean hasComplexGlyphs(GlyphVector gv) { + return !glyphsAreLTR(gv) && !glyphsAreRTL(gv); + } +} + +/* +rect getPixelBounds(frc, x, y) +rect getGlyphPixelBounds(frc, int, x, y) +getGlyphOutline(int index, x, y) +getGlyphInfo() +*/ diff --git a/jdk/test/java/awt/font/Underline/UnderlineTest.java b/jdk/test/java/awt/font/Underline/UnderlineTest.java new file mode 100644 index 00000000000..101164affd7 --- /dev/null +++ b/jdk/test/java/awt/font/Underline/UnderlineTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/** + * @test + * @bug 6216010 + * @summary check to see that underline thickness scales. + * @run main UnderlineTest + */ + +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.font.TextAttribute; +import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; +import java.util.HashMap; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JScrollPane; + +public class UnderlineTest { + static class FontsPanel extends Container { + FontsPanel(Font[] fonts) { + setLayout(new GridLayout(0, 1)); + for (int i = 0; i < fonts.length; ++i) { + add(new FontPanel(fonts[i])); + } + } + } + + static String fps = "Stellar glyphs"; + static Dimension fpd = new Dimension(600, 120); + static class FontPanel extends JComponent { + Font f; + FontPanel(Font f) { + this.f = f; + setPreferredSize(fpd); + setMinimumSize(fpd); + setMaximumSize(fpd); + setSize(fpd); + } + + public void paintComponent(Graphics g) { + g.setColor(Color.WHITE); + g.fillRect(0, 0, fpd.width, fpd.height); + + g.setColor(Color.RED); + FontRenderContext frc = ((Graphics2D)g).getFontRenderContext(); + LineMetrics lm = f.getLineMetrics(fps, frc); + int h = (int)(fpd.height - 20 - lm.getAscent()); + g.drawLine(20, h, fpd.width - 20, h); + h = fpd.height - 20; + g.drawLine(20, h, fpd.width - 20, h); + h = (int)(fpd.height - 20 + lm.getDescent()); + g.drawLine(20, h, fpd.width - 20, h); + + g.setColor(Color.BLACK); + g.setFont(f); + g.drawString(fps, 50, fpd.height - 20); + } + } + + public static void main(String args[]) { + String fontName = "Lucida Sans"; + if (args.length > 0) { + fontName = args[0]; + } + FontRenderContext frc = new FontRenderContext(null, false, false); + FontRenderContext frc2 = new FontRenderContext(AffineTransform.getScaleInstance(1.5, 1.5), false, false); + + Font font0 = new Font(fontName, 0, 20); + HashMap map = new HashMap(); + map.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); + map.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON); + Font font = font0.deriveFont(map); + + System.out.println("Using font: " + font); + + double rot = -Math.PI/4; + AffineTransform scrtx = AffineTransform.getRotateInstance(rot); + scrtx.scale(1, 2); + + Font[] fonts = { + font.deriveFont(1f), + font.deriveFont(20f), + font.deriveFont(40f), + font.deriveFont(80f), + font.deriveFont(AffineTransform.getRotateInstance(rot)), + font.deriveFont(AffineTransform.getScaleInstance(1, 2)), + font.deriveFont(AffineTransform.getScaleInstance(2, 4)), + font.deriveFont(scrtx), + }; + + LineMetrics[] metrics = new LineMetrics[fonts.length * 2]; + for (int i = 0; i < metrics.length; ++i) { + Font f = fonts[i % fonts.length]; + FontRenderContext frcx = i < fonts.length ? frc : frc2; + metrics[i] = f.getLineMetrics("X", frcx); + // dumpMetrics("Metrics for " + f.getSize2D() + " pt. font,\n tx: " + + // f.getTransform() + ",\n frctx: " + frcx.getTransform(), metrics[i]); + } + + // test for linear scale + // this seems to work, might need to get fancy to deal with last-significant-bit issues? + double ds1 = metrics[2].getStrikethroughOffset() - metrics[1].getStrikethroughOffset(); + double du1 = metrics[2].getUnderlineThickness() - metrics[1].getUnderlineThickness(); + double ds2 = metrics[3].getStrikethroughOffset() - metrics[2].getStrikethroughOffset(); + double du2 = metrics[3].getUnderlineThickness() - metrics[2].getUnderlineThickness(); + if (ds2 != ds1 * 2 || du2 != du1 * 2) { + throw new IllegalStateException("non-linear scale: " + ds1 + " / " + ds2 + ", " + + du1 + " / " + du2); + } + + JFrame jf = new JFrame("Fonts"); + jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + jf.add(new JScrollPane(new FontsPanel(fonts))); + jf.pack(); + jf.setVisible(true); + } + + static void dumpMetrics(String header, LineMetrics lm) { + if (header != null) { + System.out.println(header); + } + System.out.println("asc: " + lm.getAscent()); + System.out.println("dsc: " + lm.getDescent()); + System.out.println("ulo: " + lm.getUnderlineOffset()); + System.out.println("ult: " + lm.getUnderlineThickness()); + System.out.println("sto: " + lm.getStrikethroughOffset()); + System.out.println("stt: " + lm.getStrikethroughThickness()); + } +} diff --git a/jdk/test/java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java b/jdk/test/java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java index 4a8d3c5e14a..7620e75a2bc 100644 --- a/jdk/test/java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java +++ b/jdk/test/java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java @@ -26,6 +26,8 @@ @bug 6359129 @summary REGRESSION: Popup menus dont respond to selections when extend outside Applet @author oleg.sukhodolsky area=awt.grab + @modules java.desktop/java.awt.peer + java.desktop/sun.awt @library ../../regtesthelpers @build Util UtilInternal @run main EmbeddedFrameTest1 diff --git a/jdk/test/java/awt/xembed/server/TestXEmbedServer.java b/jdk/test/java/awt/xembed/server/TestXEmbedServer.java index 236ce0fd4df..b63cc4ad5fd 100644 --- a/jdk/test/java/awt/xembed/server/TestXEmbedServer.java +++ b/jdk/test/java/awt/xembed/server/TestXEmbedServer.java @@ -27,6 +27,8 @@ import javax.swing.*; import java.io.*; import java.util.logging.*; import sun.awt.WindowIDProvider; +import sun.awt.AWTAccessor; +import sun.awt.AWTAccessor.ComponentAccessor; import java.awt.dnd.*; import java.awt.datatransfer.*; @@ -182,7 +184,8 @@ public abstract class TestXEmbedServer { client.setBackground(new Color(30, 220, 40)); clientCont.add(client); clientCont.validate(); - WindowIDProvider pid = (WindowIDProvider)client.getPeer(); + final ComponentAccessor acc = AWTAccessor.getComponentAccessor(); + WindowIDProvider pid = (WindowIDProvider)acc.getPeer(client); log.fine("Added XEmbed server(Canvas) with X window ID " + pid.getWindow()); Rectangle toFocusBounds = toFocus.getBounds(); toFocusBounds.setLocation(toFocus.getLocationOnScreen()); diff --git a/jdk/test/javax/swing/JFileChooser/8080628/bug8080628.java b/jdk/test/javax/swing/JFileChooser/8080628/bug8080628.java index fc72ef2fc96..18760ebd91a 100644 --- a/jdk/test/javax/swing/JFileChooser/8080628/bug8080628.java +++ b/jdk/test/javax/swing/JFileChooser/8080628/bug8080628.java @@ -33,6 +33,7 @@ import sun.swing.SwingUtilities2; * @bug 8080628 * @summary No mnemonics on Open and Save buttons in JFileChooser. * @author Alexey Ivanov + * @modules java.desktop/sun.swing * @run main bug8080628 */ public class bug8080628 { diff --git a/jdk/test/javax/swing/RepaintManager/6608456/bug6608456.java b/jdk/test/javax/swing/RepaintManager/6608456/bug6608456.java index 92a430412bd..40a7091665b 100644 --- a/jdk/test/javax/swing/RepaintManager/6608456/bug6608456.java +++ b/jdk/test/javax/swing/RepaintManager/6608456/bug6608456.java @@ -25,6 +25,7 @@ * * @bug 6608456 * @author Igor Kushnirskiy + * @modules java.desktop/com.sun.java.swing * @summary tests if delegate RepaintManager gets invoked. */ diff --git a/jdk/test/javax/swing/RepaintManager/DisplayListenerLeak/DisplayListenerLeak.java b/jdk/test/javax/swing/RepaintManager/DisplayListenerLeak/DisplayListenerLeak.java index ea924bb5541..dcd5b77a636 100644 --- a/jdk/test/javax/swing/RepaintManager/DisplayListenerLeak/DisplayListenerLeak.java +++ b/jdk/test/javax/swing/RepaintManager/DisplayListenerLeak/DisplayListenerLeak.java @@ -34,6 +34,7 @@ import sun.java2d.SunGraphicsEnvironment; /** * @test * @bug 8041654 + * @modules java.desktop/sun.java2d * @run main/othervm -Xmx80m DisplayListenerLeak */ public final class DisplayListenerLeak { @@ -79,4 +80,4 @@ public final class DisplayListenerLeak { throw new RuntimeException(); } } -} \ No newline at end of file +} diff --git a/jdk/test/sun/java2d/SunGraphicsEnvironment/TestSGEuseAlternateFontforJALocales.java b/jdk/test/sun/java2d/SunGraphicsEnvironment/TestSGEuseAlternateFontforJALocales.java index 46092bb8360..b21d977f496 100644 --- a/jdk/test/sun/java2d/SunGraphicsEnvironment/TestSGEuseAlternateFontforJALocales.java +++ b/jdk/test/sun/java2d/SunGraphicsEnvironment/TestSGEuseAlternateFontforJALocales.java @@ -28,6 +28,7 @@ * @summary verify the existence of the method * SunGraphicsEnvironment.useAlternateFontforJALocales * + * @modules java.desktop/sun.java2d * @run main/othervm TestSGEuseAlternateFontforJALocales * @run main/othervm -Dfile.encoding=windows-31j -Duser.language=ja -Duser.country=JA TestSGEuseAlternateFontforJALocales * From ffbfb8f10b08d433d407050c862821cd2c8ab92e Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 3 Jul 2015 16:39:45 +0300 Subject: [PATCH 17/21] 7188942: Remove support of pbuffers in OGL Java2d pipeline Reviewed-by: prr, flar --- .../sun/java2d/opengl/CGLGraphicsConfig.java | 20 +- .../sun/java2d/opengl/CGLSurfaceData.java | 7 +- .../opengl/CGLVolatileSurfaceManager.java | 24 +-- .../java2d/opengl/CGLGraphicsConfig.m | 18 +- .../java2d/opengl/CGLSurfaceData.h | 3 +- .../java2d/opengl/CGLSurfaceData.m | 147 +-------------- .../sun/awt/image/VolatileSurfaceManager.java | 4 +- .../classes/sun/java2d/opengl/OGLContext.java | 8 +- .../sun/java2d/opengl/OGLSurfaceData.java | 18 +- .../sun/java2d/opengl/OGLUtilities.java | 3 +- .../sun/java2d/pipe/hw/AccelSurface.java | 5 +- .../native/common/java2d/opengl/OGLContext.h | 4 +- .../common/java2d/opengl/OGLSurfaceData.h | 5 +- .../sun/java2d/opengl/GLXGraphicsConfig.java | 20 +- .../sun/java2d/opengl/GLXSurfaceData.java | 10 +- .../opengl/GLXVolatileSurfaceManager.java | 24 +-- .../common/java2d/opengl/GLXGraphicsConfig.c | 8 +- .../common/java2d/opengl/GLXSurfaceData.c | 86 +-------- .../sun/java2d/opengl/WGLGraphicsConfig.java | 21 +-- .../sun/java2d/opengl/WGLSurfaceData.java | 5 +- .../opengl/WGLVolatileSurfaceManager.java | 29 ++- .../libawt/java2d/opengl/WGLGraphicsConfig.c | 11 +- .../libawt/java2d/opengl/WGLSurfaceData.c | 178 +----------------- .../VolatileImage/BitmaskVolatileImage.java | 93 +++++++++ 24 files changed, 182 insertions(+), 569 deletions(-) create mode 100644 jdk/test/java/awt/image/VolatileImage/BitmaskVolatileImage.java diff --git a/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java b/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java index b5ae3b80265..0e766e4e2be 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java +++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -379,23 +379,11 @@ public final class CGLGraphicsConfig extends CGraphicsConfig public VolatileImage createCompatibleVolatileImage(int width, int height, int transparency, int type) { - if (type == FLIP_BACKBUFFER || type == WINDOW || type == UNDEFINED || - transparency == Transparency.BITMASK) - { + if ((type != FBOBJECT && type != TEXTURE) + || transparency == Transparency.BITMASK + || type == FBOBJECT && !isCapPresent(CAPS_EXT_FBOBJECT)) { return null; } - - if (type == FBOBJECT) { - if (!isCapPresent(CAPS_EXT_FBOBJECT)) { - return null; - } - } else if (type == PBUFFER) { - boolean isOpaque = transparency == Transparency.OPAQUE; - if (!isOpaque && !isCapPresent(CAPS_STORED_ALPHA)) { - return null; - } - } - SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height, transparency, type); Surface sd = vi.getDestSurface(); diff --git a/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java b/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java index 754e8f2a26b..3aaa1bcf31b 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java +++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * 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,9 +51,6 @@ public abstract class CGLSurfaceData extends OGLSurfaceData { private native void initOps(long pConfigInfo, long pPeerData, long layerPtr, int xoff, int yoff, boolean isOpaque); - protected native boolean initPbuffer(long pData, long pConfigInfo, - boolean isOpaque, int width, int height); - protected CGLSurfaceData(CGLGraphicsConfig gc, ColorModel cm, int type, int width, int height) { super(gc, cm, type); @@ -139,7 +136,7 @@ public abstract class CGLSurfaceData extends OGLSurfaceData { /** * Creates a SurfaceData object representing an off-screen buffer (either a - * Pbuffer or Texture). + * FBO or Texture). */ public static CGLOffScreenSurfaceData createData(CGLGraphicsConfig gc, int width, int height, ColorModel cm, Image image, int type) { diff --git a/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLVolatileSurfaceManager.java b/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLVolatileSurfaceManager.java index 9071f40ae57..8148ece1f3f 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLVolatileSurfaceManager.java +++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLVolatileSurfaceManager.java @@ -45,7 +45,7 @@ import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.*; public class CGLVolatileSurfaceManager extends VolatileSurfaceManager { - private boolean accelerationEnabled; + private final boolean accelerationEnabled; public CGLVolatileSurfaceManager(SunVolatileImage vImg, Object context) { super(vImg, context); @@ -53,18 +53,13 @@ public class CGLVolatileSurfaceManager extends VolatileSurfaceManager { /* * We will attempt to accelerate this image only under the * following conditions: - * - the image is opaque OR - * - the image is translucent AND - * - the GraphicsConfig supports the FBO extension OR - * - the GraphicsConfig has a stored alpha channel + * - the image is not bitmask AND the GraphicsConfig supports the FBO + * extension */ int transparency = vImg.getTransparency(); - CGLGraphicsConfig gc = (CGLGraphicsConfig)vImg.getGraphicsConfig(); - accelerationEnabled = - (transparency == Transparency.OPAQUE) || - ((transparency == Transparency.TRANSLUCENT) && - (gc.isCapPresent(CAPS_EXT_FBOBJECT) || - gc.isCapPresent(CAPS_STORED_ALPHA))); + CGLGraphicsConfig gc = (CGLGraphicsConfig) vImg.getGraphicsConfig(); + accelerationEnabled = gc.isCapPresent(CAPS_EXT_FBOBJECT) + && transparency != Transparency.BITMASK; } protected boolean isAccelerationEnabled() { @@ -72,7 +67,7 @@ public class CGLVolatileSurfaceManager extends VolatileSurfaceManager { } /** - * Create a pbuffer-based SurfaceData object (or init the backbuffer + * Create a FBO-based SurfaceData object (or init the backbuffer * of an existing window if this is a double buffered GraphicsConfig) */ protected SurfaceData initAcceleratedSurface() { @@ -113,10 +108,9 @@ public class CGLVolatileSurfaceManager extends VolatileSurfaceManager { ColorModel cm = gc.getColorModel(vImg.getTransparency()); int type = vImg.getForcedAccelSurfaceType(); // if acceleration type is forced (type != UNDEFINED) then - // use the forced type, otherwise choose one based on caps + // use the forced type, otherwise choose FBOBJECT if (type == OGLSurfaceData.UNDEFINED) { - type = gc.isCapPresent(CAPS_EXT_FBOBJECT) ? - OGLSurfaceData.FBOBJECT : OGLSurfaceData.PBUFFER; + type = OGLSurfaceData.FBOBJECT; } if (createVSynced) { // TODO: modify parameter to delegate diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLGraphicsConfig.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLGraphicsConfig.m index 1ad7d042e6a..241f66e11ac 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLGraphicsConfig.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLGraphicsConfig.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * 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,7 +63,7 @@ OGLGC_DestroyOGLGraphicsConfig(jlong pConfigInfo) CGLCtxInfo *ctxinfo = (CGLCtxInfo *)oglc->ctxInfo; if (ctxinfo != NULL) { - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; [NSOpenGLContext clearCurrentContext]; [ctxinfo->context clearDrawable]; [ctxinfo->context release]; @@ -342,18 +342,10 @@ Java_sun_java2d_opengl_CGLGraphicsConfig_getCGLConfigInfo if (value != 0) { caps |= CAPS_DOUBLEBUFFERED; } - [sharedPixelFormat - getValues: &value - forAttribute: NSOpenGLPFAAlphaSize - forVirtualScreen: contextVirtualScreen]; - if (value != 0) { - caps |= CAPS_STORED_ALPHA; - } - J2dRlsTraceLn2(J2D_TRACE_INFO, - "CGLGraphicsConfig_getCGLConfigInfo: db=%d alpha=%d", - (caps & CAPS_DOUBLEBUFFERED) != 0, - (caps & CAPS_STORED_ALPHA) != 0); + J2dRlsTraceLn1(J2D_TRACE_INFO, + "CGLGraphicsConfig_getCGLConfigInfo: db=%d", + (caps & CAPS_DOUBLEBUFFERED) != 0); // remove before shipping (?) #if 1 diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.h b/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.h index cd809dcb52d..844e138b50a 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.h +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * 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,7 +39,6 @@ typedef struct _CGLSDOps { AWTView *peerData; CGLLayer *layer; GLclampf argb[4]; // background clear color - NSOpenGLPixelBuffer *pbuffer; CGLGraphicsConfigInfo *configInfo; } CGLSDOps; diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.m index e4dccabcf38..04dad19fb55 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,9 +110,7 @@ JNF_COCOA_EXIT(env); /** * This function disposes of any native windowing system resources associated - * with this surface. For instance, if the given OGLSDOps is of type - * OGLSD_PBUFFER, this method implementation will destroy the actual pbuffer - * surface. + * with this surface. */ void OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo) @@ -122,16 +120,7 @@ OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo) JNF_COCOA_ENTER(env); CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; - if (oglsdo->drawableType == OGLSD_PBUFFER) { - if (oglsdo->textureID != 0) { - j2d_glDeleteTextures(1, &oglsdo->textureID); - oglsdo->textureID = 0; - } - if (cglsdo->pbuffer != NULL) { - [cglsdo->pbuffer release]; - cglsdo->pbuffer = NULL; - } - } else if (oglsdo->drawableType == OGLSD_WINDOW) { + if (oglsdo->drawableType == OGLSD_WINDOW) { // detach the NSView from the NSOpenGLContext CGLGraphicsConfigInfo *cglInfo = cglsdo->configInfo; OGLContext *oglc = cglInfo->context; @@ -277,23 +266,12 @@ OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) JNF_COCOA_ENTER(env); - // set the current surface - if (dstOps->drawableType == OGLSD_PBUFFER) { - // REMIND: pbuffers are not fully tested yet... - [ctxinfo->context clearDrawable]; - [ctxinfo->context makeCurrentContext]; - [ctxinfo->context setPixelBuffer: dstCGLOps->pbuffer - cubeMapFace: 0 - mipMapLevel: 0 - currentVirtualScreen: [ctxinfo->context currentVirtualScreen]]; - } else { - CGLSDOps *cglsdo = (CGLSDOps *)dstOps->privOps; - NSView *nsView = (NSView *)cglsdo->peerData; + CGLSDOps *cglsdo = (CGLSDOps *)dstOps->privOps; + NSView *nsView = (NSView *)cglsdo->peerData; - if ([ctxinfo->context view] != nsView) { - [ctxinfo->context makeCurrentContext]; - [ctxinfo->context setView: nsView]; - } + if ([ctxinfo->context view] != nsView) { + [ctxinfo->context makeCurrentContext]; + [ctxinfo->context setView: nsView]; } if (OGLC_IS_CAP_PRESENT(oglc, CAPS_EXT_FBOBJECT)) { @@ -303,16 +281,6 @@ JNF_COCOA_ENTER(env); j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } - if ((srcOps != dstOps) && (srcOps->drawableType == OGLSD_PBUFFER)) { - // bind pbuffer to the render texture object (since we are preparing - // to copy from the pbuffer) - CGLSDOps *srcCGLOps = (CGLSDOps *)srcOps->privOps; - j2d_glBindTexture(GL_TEXTURE_2D, srcOps->textureID); - [ctxinfo->context - setTextureImageToPixelBuffer: srcCGLOps->pbuffer - colorBuffer: GL_FRONT]; - } - JNF_COCOA_EXIT(env); return oglc; @@ -464,105 +432,6 @@ Java_sun_java2d_opengl_CGLSurfaceData_clearWindow cglsdo->layer = NULL; } -JNIEXPORT jboolean JNICALL -Java_sun_java2d_opengl_CGLSurfaceData_initPbuffer - (JNIEnv *env, jobject cglsd, - jlong pData, jlong pConfigInfo, jboolean isOpaque, - jint width, jint height) -{ - J2dTraceLn3(J2D_TRACE_INFO, "CGLSurfaceData_initPbuffer: w=%d h=%d opq=%d", width, height, isOpaque); - - OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData); - if (oglsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: ops are null"); - return JNI_FALSE; - } - - CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; - if (cglsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: cgl ops are null"); - return JNI_FALSE; - } - - CGLGraphicsConfigInfo *cglInfo = (CGLGraphicsConfigInfo *) - jlong_to_ptr(pConfigInfo); - if (cglInfo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: cgl config info is null"); - return JNI_FALSE; - } - - // find the maximum allowable texture dimensions (this value ultimately - // determines our maximum pbuffer size) - int pbMax = 0; - j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &pbMax); - - int pbWidth = 0; - int pbHeight = 0; - if (OGLC_IS_CAP_PRESENT(cglInfo->context, CAPS_TEXNONPOW2)) { - // use non-power-of-two dimensions directly - pbWidth = (width <= pbMax) ? width : 0; - pbHeight = (height <= pbMax) ? height : 0; - } else { - // find the appropriate power-of-two dimensions - pbWidth = OGLSD_NextPowerOfTwo(width, pbMax); - pbHeight = OGLSD_NextPowerOfTwo(height, pbMax); - } - - J2dTraceLn3(J2D_TRACE_VERBOSE, " desired pbuffer dimensions: w=%d h=%d max=%d", pbWidth, pbHeight, pbMax); - - // if either dimension is 0, we cannot allocate a pbuffer/texture with the - // requested dimensions - if (pbWidth == 0 || pbHeight == 0) { - J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: dimensions too large"); - return JNI_FALSE; - } - - int format = isOpaque ? GL_RGB : GL_RGBA; - -JNF_COCOA_ENTER(env); - - cglsdo->pbuffer = - [[NSOpenGLPixelBuffer alloc] - initWithTextureTarget: GL_TEXTURE_2D - textureInternalFormat: format - textureMaxMipMapLevel: 0 - pixelsWide: pbWidth - pixelsHigh: pbHeight]; - if (cglsdo->pbuffer == nil) { - J2dRlsTraceLn(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: could not create pbuffer"); - return JNI_FALSE; - } - - // make sure the actual dimensions match those that we requested - GLsizei actualWidth = [cglsdo->pbuffer pixelsWide]; - GLsizei actualHeight = [cglsdo->pbuffer pixelsHigh]; - if (actualWidth != pbWidth || actualHeight != pbHeight) { - J2dRlsTraceLn2(J2D_TRACE_ERROR, "CGLSurfaceData_initPbuffer: actual (w=%d h=%d) != requested", actualWidth, actualHeight); - [cglsdo->pbuffer release]; - return JNI_FALSE; - } - - GLuint texID = 0; - j2d_glGenTextures(1, &texID); - j2d_glBindTexture(GL_TEXTURE_2D, texID); - - oglsdo->drawableType = OGLSD_PBUFFER; - oglsdo->isOpaque = isOpaque; - oglsdo->width = width; - oglsdo->height = height; - oglsdo->textureID = texID; - oglsdo->textureWidth = pbWidth; - oglsdo->textureHeight = pbHeight; - oglsdo->activeBuffer = GL_FRONT; - oglsdo->needsInit = JNI_TRUE; - - OGLSD_INIT_TEXTURE_FILTER(oglsdo, GL_NEAREST); - -JNF_COCOA_EXIT(env); - - return JNI_TRUE; -} - #pragma mark - #pragma mark "--- CGLSurfaceData methods - Mac OS X specific ---" diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/VolatileSurfaceManager.java b/jdk/src/java.desktop/share/classes/sun/awt/image/VolatileSurfaceManager.java index b20f203a16c..e3aa4fdb990 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/VolatileSurfaceManager.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/VolatileSurfaceManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -246,7 +246,7 @@ public abstract class VolatileSurfaceManager * SurfaceData object, or null if the surface creation was not successful. * * Platform-specific subclasses should initialize an accelerated - * surface (e.g. a DirectDraw surface on Windows, an OpenGL pbuffer, + * surface (e.g. a DirectDraw surface on Windows, an OpenGL FBO, * or an X11 pixmap). */ protected abstract SurfaceData initAcceleratedSurface(); diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLContext.java b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLContext.java index 2a2f660d129..d001c22228e 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLContext.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -164,9 +164,6 @@ public class OGLContext extends BufferedContext { @Native static final int CAPS_EXT_FBOBJECT = (CAPS_RT_TEXTURE_ALPHA | CAPS_RT_TEXTURE_OPAQUE); - /** Indicates that the context supports a stored alpha channel. */ - @Native - static final int CAPS_STORED_ALPHA = CAPS_RT_PLAIN_ALPHA; /** Indicates that the context is doublebuffered. */ @Native static final int CAPS_DOUBLEBUFFERED = (FIRST_PRIVATE_CAP << 0); @@ -205,9 +202,6 @@ public class OGLContext extends BufferedContext { if ((caps & CAPS_EXT_FBOBJECT) != 0) { sb.append("CAPS_EXT_FBOBJECT|"); } - if ((caps & CAPS_STORED_ALPHA) != 0) { - sb.append("CAPS_STORED_ALPHA|"); - } if ((caps & CAPS_DOUBLEBUFFERED) != 0) { sb.append("CAPS_DOUBLEBUFFERED|"); } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java index 253a3df3a73..914b97aba05 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,7 +91,6 @@ import static sun.java2d.opengl.OGLContext.OGLContextCaps.*; * OGL Type Corresponding SurfaceType * -------- ------------------------- * WINDOW OpenGLSurface - * PBUFFER OpenGLSurface * TEXTURE OpenGLTexture * FLIP_BACKBUFFER OpenGLSurface * FBOBJECT OpenGLSurfaceRTT @@ -104,7 +103,6 @@ public abstract class OGLSurfaceData extends SurfaceData * * @see sun.java2d.pipe.hw.AccelSurface */ - public static final int PBUFFER = RT_PLAIN; public static final int FBOBJECT = RT_TEXTURE; /** @@ -172,9 +170,6 @@ public abstract class OGLSurfaceData extends SurfaceData boolean texRect, int width, int height); protected native boolean initFlipBackbuffer(long pData); - protected abstract boolean initPbuffer(long pData, long pConfigInfo, - boolean isOpaque, - int width, int height); private native int getTextureTarget(long pData); private native int getTextureID(long pData); @@ -250,7 +245,6 @@ public abstract class OGLSurfaceData extends SurfaceData return OpenGLTexture; case FBOBJECT: return OpenGLSurfaceRTT; - case PBUFFER: default: return OpenGLSurface; } @@ -266,13 +260,6 @@ public abstract class OGLSurfaceData extends SurfaceData boolean success = false; switch (type) { - case PBUFFER: - success = initPbuffer(getNativeOps(), - graphicsConfig.getNativeConfigInfo(), - isOpaque, - width, height); - break; - case TEXTURE: success = initTexture(getNativeOps(), isOpaque, isTexNonPow2Available(), @@ -311,10 +298,9 @@ public abstract class OGLSurfaceData extends SurfaceData try { switch (type) { case TEXTURE: - case PBUFFER: case FBOBJECT: // need to make sure the context is current before - // creating the texture (or pbuffer, or fbobject) + // creating the texture or fbobject OGLContext.setScratchSurface(graphicsConfig); break; default: diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLUtilities.java b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLUtilities.java index b8a37dc5d22..02f9b4cef29 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLUtilities.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLUtilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ class OGLUtilities { */ public static final int UNDEFINED = OGLSurfaceData.UNDEFINED; public static final int WINDOW = OGLSurfaceData.WINDOW; - public static final int PBUFFER = OGLSurfaceData.PBUFFER; public static final int TEXTURE = OGLSurfaceData.TEXTURE; public static final int FLIP_BACKBUFFER = OGLSurfaceData.FLIP_BACKBUFFER; public static final int FBOBJECT = OGLSurfaceData.FBOBJECT; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelSurface.java b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelSurface.java index 8f4e5a3d166..ebbb716f064 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelSurface.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelSurface.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. * 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,8 +43,7 @@ public interface AccelSurface extends BufferedContextProvider, Surface { */ @Native public static final int WINDOW = 1; /** - * Render-To Plain surface (pbuffer for OpenGL, Render Target surface - * for Direct3D) + * Render-To Plain surface (Render Target surface for Direct3D) */ @Native public static final int RT_PLAIN = 2; /** diff --git a/jdk/src/java.desktop/share/native/common/java2d/opengl/OGLContext.h b/jdk/src/java.desktop/share/native/common/java2d/opengl/OGLContext.h index 27c5cec5909..85dd9e6d60c 100644 --- a/jdk/src/java.desktop/share/native/common/java2d/opengl/OGLContext.h +++ b/jdk/src/java.desktop/share/native/common/java2d/opengl/OGLContext.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,8 +122,6 @@ typedef struct { sun_java2d_opengl_OGLContext_OGLContextCaps_LAST_SHARED_CAP #define CAPS_EXT_FBOBJECT \ sun_java2d_opengl_OGLContext_OGLContextCaps_CAPS_EXT_FBOBJECT -#define CAPS_STORED_ALPHA \ - sun_java2d_opengl_OGLContext_OGLContextCaps_CAPS_STORED_ALPHA #define CAPS_DOUBLEBUFFERED \ sun_java2d_opengl_OGLContext_OGLContextCaps_CAPS_DOUBLEBUFFERED #define CAPS_EXT_LCD_SHADER \ diff --git a/jdk/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.h b/jdk/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.h index 0fc8b3b4da5..e5ce1604fbe 100644 --- a/jdk/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.h +++ b/jdk/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,7 +118,7 @@ typedef struct { * x/yOffset would be (0,0) (the same applies to pbuffers). * * jint width/height; - * The cached surface bounds. For offscreen surface types (OGLSD_PBUFFER, + * The cached surface bounds. For offscreen surface types (OGLSD_FBOBJECT, * OGLSD_TEXTURE, etc.) these values must remain constant. Onscreen window * surfaces (OGLSD_WINDOW, OGLSD_FLIP_BACKBUFFER, etc.) may have their * bounds changed in response to a programmatic or user-initiated event, so @@ -218,7 +218,6 @@ struct _OGLSDOps { */ #define OGLSD_UNDEFINED sun_java2d_pipe_hw_AccelSurface_UNDEFINED #define OGLSD_WINDOW sun_java2d_pipe_hw_AccelSurface_WINDOW -#define OGLSD_PBUFFER sun_java2d_pipe_hw_AccelSurface_RT_PLAIN #define OGLSD_TEXTURE sun_java2d_pipe_hw_AccelSurface_TEXTURE #define OGLSD_FLIP_BACKBUFFER sun_java2d_pipe_hw_AccelSurface_FLIP_BACKBUFFER #define OGLSD_FBOBJECT sun_java2d_pipe_hw_AccelSurface_RT_TEXTURE diff --git a/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java b/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java index 8ccabb478d7..660a71125b3 100644 --- a/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -399,23 +399,11 @@ public class GLXGraphicsConfig createCompatibleVolatileImage(int width, int height, int transparency, int type) { - if (type == FLIP_BACKBUFFER || type == WINDOW || type == UNDEFINED || - transparency == Transparency.BITMASK) - { + if ((type != FBOBJECT && type != TEXTURE) + || transparency == Transparency.BITMASK + || type == FBOBJECT && !isCapPresent(CAPS_EXT_FBOBJECT)) { return null; } - - if (type == FBOBJECT) { - if (!isCapPresent(CAPS_EXT_FBOBJECT)) { - return null; - } - } else if (type == PBUFFER) { - boolean isOpaque = transparency == Transparency.OPAQUE; - if (!isOpaque && !isCapPresent(CAPS_STORED_ALPHA)) { - return null; - } - } - SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height, transparency, type); Surface sd = vi.getDestSurface(); diff --git a/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXSurfaceData.java b/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXSurfaceData.java index 50e12e06993..fc7f3d90351 100644 --- a/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXSurfaceData.java +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXSurfaceData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,11 +30,10 @@ import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Rectangle; -import java.awt.Transparency; import java.awt.image.ColorModel; + import sun.awt.X11ComponentPeer; import sun.java2d.SurfaceData; -import sun.java2d.loops.SurfaceType; public abstract class GLXSurfaceData extends OGLSurfaceData { @@ -42,9 +41,6 @@ public abstract class GLXSurfaceData extends OGLSurfaceData { private GLXGraphicsConfig graphicsConfig; private native void initOps(X11ComponentPeer peer, long aData); - protected native boolean initPbuffer(long pData, long pConfigInfo, - boolean isOpaque, - int width, int height); protected GLXSurfaceData(X11ComponentPeer peer, GLXGraphicsConfig gc, ColorModel cm, int type) @@ -91,7 +87,7 @@ public abstract class GLXSurfaceData extends OGLSurfaceData { /** * Creates a SurfaceData object representing an off-screen buffer (either - * a Pbuffer or Texture). + * a FBO or Texture). */ public static GLXOffScreenSurfaceData createData(GLXGraphicsConfig gc, int width, int height, diff --git a/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXVolatileSurfaceManager.java b/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXVolatileSurfaceManager.java index 2a366f1db26..3157dfb58b9 100644 --- a/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXVolatileSurfaceManager.java +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/opengl/GLXVolatileSurfaceManager.java @@ -46,7 +46,7 @@ import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.*; public class GLXVolatileSurfaceManager extends VolatileSurfaceManager { - private boolean accelerationEnabled; + private final boolean accelerationEnabled; public GLXVolatileSurfaceManager(SunVolatileImage vImg, Object context) { super(vImg, context); @@ -54,18 +54,13 @@ public class GLXVolatileSurfaceManager extends VolatileSurfaceManager { /* * We will attempt to accelerate this image only under the * following conditions: - * - the image is opaque OR - * - the image is translucent AND - * - the GraphicsConfig supports the FBO extension OR - * - the GraphicsConfig has a stored alpha channel + * - the image is not bitmask AND the GraphicsConfig supports the FBO + * extension */ int transparency = vImg.getTransparency(); - GLXGraphicsConfig gc = (GLXGraphicsConfig)vImg.getGraphicsConfig(); - accelerationEnabled = - (transparency == Transparency.OPAQUE) || - ((transparency == Transparency.TRANSLUCENT) && - (gc.isCapPresent(CAPS_EXT_FBOBJECT) || - gc.isCapPresent(CAPS_STORED_ALPHA))); + GLXGraphicsConfig gc = (GLXGraphicsConfig) vImg.getGraphicsConfig(); + accelerationEnabled = gc.isCapPresent(CAPS_EXT_FBOBJECT) + && transparency != Transparency.BITMASK; } protected boolean isAccelerationEnabled() { @@ -73,7 +68,7 @@ public class GLXVolatileSurfaceManager extends VolatileSurfaceManager { } /** - * Create a pbuffer-based SurfaceData object (or init the backbuffer + * Create a FBO-based SurfaceData object (or init the backbuffer * of an existing window if this is a double buffered GraphicsConfig) */ protected SurfaceData initAcceleratedSurface() { @@ -113,10 +108,9 @@ public class GLXVolatileSurfaceManager extends VolatileSurfaceManager { ColorModel cm = gc.getColorModel(vImg.getTransparency()); int type = vImg.getForcedAccelSurfaceType(); // if acceleration type is forced (type != UNDEFINED) then - // use the forced type, otherwise choose one based on caps + // use the forced type, otherwise choose FBOBJECT if (type == OGLSurfaceData.UNDEFINED) { - type = gc.isCapPresent(CAPS_EXT_FBOBJECT) ? - OGLSurfaceData.FBOBJECT : OGLSurfaceData.PBUFFER; + type = OGLSurfaceData.FBOBJECT; } if (createVSynced) { sData = GLXSurfaceData.createData(peer, vImg, type); diff --git a/jdk/src/java.desktop/unix/native/common/java2d/opengl/GLXGraphicsConfig.c b/jdk/src/java.desktop/unix/native/common/java2d/opengl/GLXGraphicsConfig.c index 7f8c6ff486b..45aa6eaef47 100644 --- a/jdk/src/java.desktop/unix/native/common/java2d/opengl/GLXGraphicsConfig.c +++ b/jdk/src/java.desktop/unix/native/common/java2d/opengl/GLXGraphicsConfig.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -472,7 +472,7 @@ Java_sun_java2d_opengl_GLXGraphicsConfig_getGLXConfigInfo(JNIEnv *env, GLXPbuffer scratch; GLXGraphicsConfigInfo *glxinfo; jint caps = CAPS_EMPTY; - int db, alpha; + int db; const unsigned char *versionstr; J2dRlsTraceLn(J2D_TRACE_INFO, "GLXGraphicsConfig_getGLXConfigInfo"); @@ -583,10 +583,6 @@ Java_sun_java2d_opengl_GLXGraphicsConfig_getGLXConfigInfo(JNIEnv *env, if (db) { caps |= CAPS_DOUBLEBUFFERED; } - j2d_glXGetFBConfigAttrib(awt_display, fbconfig, GLX_ALPHA_SIZE, &alpha); - if (alpha > 0) { - caps |= CAPS_STORED_ALPHA; - } // initialize the OGLContext, which wraps the GLXFBConfig and GLXContext oglc = GLXGC_InitOGLContext(fbconfig, context, scratch, caps); diff --git a/jdk/src/java.desktop/unix/native/common/java2d/opengl/GLXSurfaceData.c b/jdk/src/java.desktop/unix/native/common/java2d/opengl/GLXSurfaceData.c index 1bdd08827f9..9ea366e46fd 100644 --- a/jdk/src/java.desktop/unix/native/common/java2d/opengl/GLXSurfaceData.c +++ b/jdk/src/java.desktop/unix/native/common/java2d/opengl/GLXSurfaceData.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,25 +111,13 @@ Java_sun_java2d_opengl_GLXSurfaceData_initOps(JNIEnv *env, jobject glxsd, /** * This function disposes of any native windowing system resources associated - * with this surface. For instance, if the given OGLSDOps is of type - * OGLSD_PBUFFER, this method implementation will destroy the actual pbuffer - * surface. + * with this surface. */ void OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo) { - GLXSDOps *glxsdo = (GLXSDOps *)oglsdo->privOps; - J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface"); - - if (oglsdo->drawableType == OGLSD_PBUFFER) { - if (glxsdo->drawable != 0) { - j2d_glXDestroyPbuffer(awt_display, glxsdo->drawable); - glxsdo->drawable = 0; - } - } else if (oglsdo->drawableType == OGLSD_WINDOW) { - // X Window is free'd later by AWT code... - } + // X Window is free'd later by AWT code... } /** @@ -358,74 +346,6 @@ GLXSD_BadAllocXErrHandler(Display *display, XErrorEvent *xerr) return 0; } -JNIEXPORT jboolean JNICALL -Java_sun_java2d_opengl_GLXSurfaceData_initPbuffer - (JNIEnv *env, jobject glxsd, - jlong pData, jlong pConfigInfo, - jboolean isOpaque, - jint width, jint height) -{ - OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData); - GLXGraphicsConfigInfo *glxinfo = - (GLXGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); - GLXSDOps *glxsdo; - GLXPbuffer pbuffer; - int attrlist[] = {GLX_PBUFFER_WIDTH, 0, - GLX_PBUFFER_HEIGHT, 0, - GLX_PRESERVED_CONTENTS, GL_FALSE, 0}; - - J2dTraceLn3(J2D_TRACE_INFO, - "GLXSurfaceData_initPbuffer: w=%d h=%d opq=%d", - width, height, isOpaque); - - if (oglsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "GLXSurfaceData_initPbuffer: ops are null"); - return JNI_FALSE; - } - - glxsdo = (GLXSDOps *)oglsdo->privOps; - if (glxsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "GLXSurfaceData_initPbuffer: glx ops are null"); - return JNI_FALSE; - } - - if (glxinfo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "GLXSurfaceData_initPbuffer: glx config info is null"); - return JNI_FALSE; - } - - attrlist[1] = width; - attrlist[3] = height; - - surfaceCreationFailed = JNI_FALSE; - EXEC_WITH_XERROR_HANDLER( - GLXSD_BadAllocXErrHandler, - pbuffer = j2d_glXCreatePbuffer(awt_display, - glxinfo->fbconfig, attrlist)); - if ((pbuffer == 0) || surfaceCreationFailed) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "GLXSurfaceData_initPbuffer: could not create glx pbuffer"); - return JNI_FALSE; - } - - oglsdo->drawableType = OGLSD_PBUFFER; - oglsdo->isOpaque = isOpaque; - oglsdo->width = width; - oglsdo->height = height; - oglsdo->xOffset = 0; - oglsdo->yOffset = 0; - - glxsdo->drawable = pbuffer; - glxsdo->xdrawable = 0; - - OGLSD_SetNativeDimensions(env, oglsdo, width, height); - - return JNI_TRUE; -} - void OGLSD_SwapBuffers(JNIEnv *env, jlong window) { diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java b/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java index c5682881005..ec42d3142ad 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. * 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 @@ package sun.java2d.opengl; import java.awt.AWTException; import java.awt.BufferCapabilities; -import java.awt.BufferCapabilities.FlipContents; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; @@ -425,23 +424,11 @@ public class WGLGraphicsConfig createCompatibleVolatileImage(int width, int height, int transparency, int type) { - if (type == FLIP_BACKBUFFER || type == WINDOW || type == UNDEFINED || - transparency == Transparency.BITMASK) - { + if ((type != FBOBJECT && type != TEXTURE) + || transparency == Transparency.BITMASK + || type == FBOBJECT && !isCapPresent(CAPS_EXT_FBOBJECT)) { return null; } - - if (type == FBOBJECT) { - if (!isCapPresent(CAPS_EXT_FBOBJECT)) { - return null; - } - } else if (type == PBUFFER) { - boolean isOpaque = transparency == Transparency.OPAQUE; - if (!isOpaque && !isCapPresent(CAPS_STORED_ALPHA)) { - return null; - } - } - SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height, transparency, type); Surface sd = vi.getDestSurface(); diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java b/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java index 75b691c54a5..b415cf8f36d 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. * 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,9 +43,6 @@ public abstract class WGLSurfaceData extends OGLSurfaceData { private native void initOps(long pConfigInfo, WComponentPeer peer, long hwnd); - protected native boolean initPbuffer(long pData, long pConfigInfo, - boolean isOpaque, - int width, int height); protected WGLSurfaceData(WComponentPeer peer, WGLGraphicsConfig gc, ColorModel cm, int type) diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java b/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java index 53f5b04783a..0bcd3e95dea 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLVolatileSurfaceManager.java @@ -43,10 +43,9 @@ import static sun.java2d.pipe.hw.AccelSurface.*; import sun.java2d.pipe.hw.ExtendedBufferCapabilities; import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.*; -public class WGLVolatileSurfaceManager - extends VolatileSurfaceManager -{ - private boolean accelerationEnabled; +public class WGLVolatileSurfaceManager extends VolatileSurfaceManager { + + private final boolean accelerationEnabled; public WGLVolatileSurfaceManager(SunVolatileImage vImg, Object context) { super(vImg, context); @@ -54,18 +53,13 @@ public class WGLVolatileSurfaceManager /* * We will attempt to accelerate this image only under the * following conditions: - * - the image is opaque OR - * - the image is translucent AND - * - the GraphicsConfig supports the FBO extension OR - * - the GraphicsConfig has a stored alpha channel + * - the image is not bitmask AND the GraphicsConfig supports the FBO + * extension */ int transparency = vImg.getTransparency(); - WGLGraphicsConfig gc = (WGLGraphicsConfig)vImg.getGraphicsConfig(); - accelerationEnabled = - (transparency == Transparency.OPAQUE) || - ((transparency == Transparency.TRANSLUCENT) && - (gc.isCapPresent(CAPS_EXT_FBOBJECT) || - gc.isCapPresent(CAPS_STORED_ALPHA))); + WGLGraphicsConfig gc = (WGLGraphicsConfig) vImg.getGraphicsConfig(); + accelerationEnabled = gc.isCapPresent(CAPS_EXT_FBOBJECT) + && transparency != Transparency.BITMASK; } protected boolean isAccelerationEnabled() { @@ -73,7 +67,7 @@ public class WGLVolatileSurfaceManager } /** - * Create a pbuffer-based SurfaceData object (or init the backbuffer + * Create a FBO-based SurfaceData object (or init the backbuffer * of an existing window if this is a double buffered GraphicsConfig). */ protected SurfaceData initAcceleratedSurface() { @@ -111,10 +105,9 @@ public class WGLVolatileSurfaceManager ColorModel cm = gc.getColorModel(vImg.getTransparency()); int type = vImg.getForcedAccelSurfaceType(); // if acceleration type is forced (type != UNDEFINED) then - // use the forced type, otherwise choose one based on caps + // use the forced type, otherwise choose FBOBJECT if (type == OGLSurfaceData.UNDEFINED) { - type = gc.isCapPresent(CAPS_EXT_FBOBJECT) ? - OGLSurfaceData.FBOBJECT : OGLSurfaceData.PBUFFER; + type = OGLSurfaceData.FBOBJECT; } if (createVSynced) { sData = WGLSurfaceData.createData(peer, vImg, type); diff --git a/jdk/src/java.desktop/windows/native/libawt/java2d/opengl/WGLGraphicsConfig.c b/jdk/src/java.desktop/windows/native/libawt/java2d/opengl/WGLGraphicsConfig.c index 31ab9e87569..0b495738a5a 100644 --- a/jdk/src/java.desktop/windows/native/libawt/java2d/opengl/WGLGraphicsConfig.c +++ b/jdk/src/java.desktop/windows/native/libawt/java2d/opengl/WGLGraphicsConfig.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -502,8 +502,8 @@ Java_sun_java2d_opengl_WGLGraphicsConfig_getWGLConfigInfo(JNIEnv *env, const unsigned char *versionstr; const char *extstr; jint caps = CAPS_EMPTY; - int attrKeys[] = { WGL_DOUBLE_BUFFER_ARB, WGL_ALPHA_BITS_ARB }; - int attrVals[2]; + int attrKeys[] = { WGL_DOUBLE_BUFFER_ARB}; + int attrVals[1]; J2dRlsTraceLn(J2D_TRACE_INFO, "WGLGraphicsConfig_getWGLConfigInfo"); @@ -624,13 +624,10 @@ Java_sun_java2d_opengl_WGLGraphicsConfig_getWGLConfigInfo(JNIEnv *env, } // get config-specific capabilities - j2d_wglGetPixelFormatAttribivARB(hdc, pixfmt, 0, 2, attrKeys, attrVals); + j2d_wglGetPixelFormatAttribivARB(hdc, pixfmt, 0, 1, attrKeys, attrVals); if (attrVals[0]) { caps |= CAPS_DOUBLEBUFFERED; } - if (attrVals[1] > 0) { - caps |= CAPS_STORED_ALPHA; - } // create the scratch pbuffer scratch = j2d_wglCreatePbufferARB(hdc, pixfmt, 1, 1, NULL); diff --git a/jdk/src/java.desktop/windows/native/libawt/java2d/opengl/WGLSurfaceData.c b/jdk/src/java.desktop/windows/native/libawt/java2d/opengl/WGLSurfaceData.c index d316a63ead7..3496252553b 100644 --- a/jdk/src/java.desktop/windows/native/libawt/java2d/opengl/WGLSurfaceData.c +++ b/jdk/src/java.desktop/windows/native/libawt/java2d/opengl/WGLSurfaceData.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. * 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,28 +107,13 @@ Java_sun_java2d_opengl_WGLSurfaceData_initOps(JNIEnv *env, jobject wglsd, /** * This function disposes of any native windowing system resources associated - * with this surface. For instance, if the given OGLSDOps is of type - * OGLSD_PBUFFER, this method implementation will destroy the actual pbuffer - * surface. + * with this surface. */ void OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo) { - WGLSDOps *wglsdo = (WGLSDOps *)oglsdo->privOps; - J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface"); - - if (oglsdo->drawableType == OGLSD_PBUFFER) { - if (wglsdo->pbuffer != 0) { - if (wglsdo->pbufferDC != 0) { - j2d_wglReleasePbufferDCARB(wglsdo->pbuffer, - wglsdo->pbufferDC); - wglsdo->pbufferDC = 0; - } - j2d_wglDestroyPbufferARB(wglsdo->pbuffer); - wglsdo->pbuffer = 0; - } - } + // Window is free'd later by AWT code... } /** @@ -276,19 +261,11 @@ OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) ctxinfo = (WGLCtxInfo *)oglc->ctxInfo; // get the hdc for the destination surface - if (dstOps->drawableType == OGLSD_PBUFFER) { - dstHDC = dstWGLOps->pbufferDC; - } else { - dstHDC = GetDC(dstWGLOps->window); - } + dstHDC = GetDC(dstWGLOps->window); // get the hdc for the source surface - if (srcOps->drawableType == OGLSD_PBUFFER) { - srcHDC = srcWGLOps->pbufferDC; - } else { - // the source will always be equal to the destination in this case - srcHDC = dstHDC; - } + // the source will always be equal to the destination in this case + srcHDC = dstHDC; // REMIND: in theory we should be able to use wglMakeContextCurrentARB() // even when the src/dst surfaces are the same, but this causes problems @@ -306,9 +283,7 @@ OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) if (!success) { J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_MakeOGLContextCurrent: could not make current"); - if (dstOps->drawableType != OGLSD_PBUFFER) { - ReleaseDC(dstWGLOps->window, dstHDC); - } + ReleaseDC(dstWGLOps->window, dstHDC); return NULL; } @@ -319,9 +294,7 @@ OGLSD_MakeOGLContextCurrent(JNIEnv *env, OGLSDOps *srcOps, OGLSDOps *dstOps) j2d_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } - if (dstOps->drawableType != OGLSD_PBUFFER) { - ReleaseDC(dstWGLOps->window, dstHDC); - } + ReleaseDC(dstWGLOps->window, dstHDC); return oglc; } @@ -400,141 +373,6 @@ OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo) return JNI_TRUE; } -JNIEXPORT jboolean JNICALL -Java_sun_java2d_opengl_WGLSurfaceData_initPbuffer - (JNIEnv *env, jobject wglsd, - jlong pData, jlong pConfigInfo, - jboolean isOpaque, - jint width, jint height) -{ - int attrKeys[] = { - WGL_MAX_PBUFFER_WIDTH_ARB, - WGL_MAX_PBUFFER_HEIGHT_ARB, - }; - int attrVals[2]; - int pbAttrList[] = { 0 }; - OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData); - WGLGraphicsConfigInfo *wglInfo = - (WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo); - WGLSDOps *wglsdo; - HWND hwnd; - HDC hdc, pbufferDC; - HPBUFFERARB pbuffer; - int maxWidth, maxHeight; - int actualWidth, actualHeight; - - J2dTraceLn3(J2D_TRACE_INFO, - "WGLSurfaceData_initPbuffer: w=%d h=%d opq=%d", - width, height, isOpaque); - - if (oglsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "WGLSurfaceData_initPbuffer: ops are null"); - return JNI_FALSE; - } - - wglsdo = (WGLSDOps *)oglsdo->privOps; - if (wglsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "WGLSurfaceData_initPbuffer: wgl ops are null"); - return JNI_FALSE; - } - - if (wglInfo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "WGLSurfaceData_initPbuffer: wgl config info is null"); - return JNI_FALSE; - } - - // create a scratch window - hwnd = WGLGC_CreateScratchWindow(wglInfo->screen); - if (hwnd == 0) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "WGLSurfaceData_initPbuffer: could not create scratch window"); - return JNI_FALSE; - } - - // get the HDC for the scratch window - hdc = GetDC(hwnd); - if (hdc == 0) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "WGLSurfaceData_initPbuffer: could not get dc for scratch window"); - DestroyWindow(hwnd); - return JNI_FALSE; - } - - // get the maximum allowable pbuffer dimensions - j2d_wglGetPixelFormatAttribivARB(hdc, wglInfo->pixfmt, 0, 2, - attrKeys, attrVals); - maxWidth = attrVals[0]; - maxHeight = attrVals[1]; - - J2dTraceLn4(J2D_TRACE_VERBOSE, - " desired pbuffer dimensions: w=%d h=%d maxw=%d maxh=%d", - width, height, maxWidth, maxHeight); - - // if either dimension is 0 or larger than the maximum, we cannot - // allocate a pbuffer with the requested dimensions - if (width == 0 || width > maxWidth || - height == 0 || height > maxHeight) - { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "WGLSurfaceData_initPbuffer: invalid dimensions"); - ReleaseDC(hwnd, hdc); - DestroyWindow(hwnd); - return JNI_FALSE; - } - - pbuffer = j2d_wglCreatePbufferARB(hdc, wglInfo->pixfmt, - width, height, pbAttrList); - - ReleaseDC(hwnd, hdc); - DestroyWindow(hwnd); - - if (pbuffer == 0) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "WGLSurfaceData_initPbuffer: could not create wgl pbuffer"); - return JNI_FALSE; - } - - // note that we get the DC for the pbuffer at creation time, and then - // release the DC when the pbuffer is disposed; the WGL_ARB_pbuffer - // spec is vague about such things, but from past experience we know - // this approach to be more robust than, for example, doing a - // Get/ReleasePbufferDC() everytime we make a context current - pbufferDC = j2d_wglGetPbufferDCARB(pbuffer); - if (pbufferDC == 0) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "WGLSurfaceData_initPbuffer: could not get dc for pbuffer"); - j2d_wglDestroyPbufferARB(pbuffer); - return JNI_FALSE; - } - - // make sure the actual dimensions match those that we requested - j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_WIDTH_ARB, &actualWidth); - j2d_wglQueryPbufferARB(pbuffer, WGL_PBUFFER_HEIGHT_ARB, &actualHeight); - - if (width != actualWidth || height != actualHeight) { - J2dRlsTraceLn2(J2D_TRACE_ERROR, - "WGLSurfaceData_initPbuffer: actual (w=%d h=%d) != requested", - actualWidth, actualHeight); - j2d_wglReleasePbufferDCARB(pbuffer, pbufferDC); - j2d_wglDestroyPbufferARB(pbuffer); - return JNI_FALSE; - } - - oglsdo->drawableType = OGLSD_PBUFFER; - oglsdo->isOpaque = isOpaque; - oglsdo->width = width; - oglsdo->height = height; - wglsdo->pbuffer = pbuffer; - wglsdo->pbufferDC = pbufferDC; - - OGLSD_SetNativeDimensions(env, oglsdo, width, height); - - return JNI_TRUE; -} - void OGLSD_SwapBuffers(JNIEnv *env, jlong pPeerData) { diff --git a/jdk/test/java/awt/image/VolatileImage/BitmaskVolatileImage.java b/jdk/test/java/awt/image/VolatileImage/BitmaskVolatileImage.java new file mode 100644 index 00000000000..4d05ad54b61 --- /dev/null +++ b/jdk/test/java/awt/image/VolatileImage/BitmaskVolatileImage.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; + +import static java.awt.Transparency.BITMASK; + +/** + * @test + * @bug 7188942 + * @summary We should get correct volatile image, when we use BITMASK + * transparency + */ +public final class BitmaskVolatileImage { + + public static final int S = 8; + + public static void main(final String[] args) { + GraphicsConfiguration gc = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + VolatileImage vi = gc.createCompatibleVolatileImage(S, S, BITMASK); + BufferedImage ci = gc.createCompatibleImage(S, S, BITMASK); + + int attempt = 0; + do { + if (++attempt > 10) { + throw new RuntimeException("Too many attempts: " + attempt); + } + vi.validate(gc); + test(vi, ci, gc); + } while (vi.contentsLost()); + } + + private static void test(VolatileImage vi, BufferedImage ci, GraphicsConfiguration gc) { + for (int r = 0; r <= 255; ++r) { + for (int a = 0; a <= 255; ++a) { + fill(vi, new Color(r, 0, 0, a)); + fill(ci, new Color(r, 0, 0, a)); + validate(ci, vi.getSnapshot()); + } + } + } + + private static void fill(Image image, Color color) { + Graphics2D g2d = (Graphics2D) image.getGraphics(); + g2d.setColor(color); + g2d.setComposite(AlphaComposite.Src); + g2d.fillRect(0, 0, S, S); + g2d.dispose(); + } + + private static void validate(BufferedImage ci, BufferedImage snapshot) { + for (int y = 0; y < ci.getHeight(); y++) { + for (int x = 0; x < ci.getWidth(); x++) { + int ci_rgb = ci.getRGB(x, y); + int vi_rgb = snapshot.getRGB(x, y); + if (ci_rgb != vi_rgb) { + System.err.println("Exp:" + Integer.toHexString(ci_rgb)); + System.err.println("Actual:" + Integer.toHexString(vi_rgb)); + throw new RuntimeException("Colors mismatch!"); + } + } + } + } +} From 2e3073a8abc8c403c245e0de7400065f83057f3a Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Mon, 6 Jul 2015 18:15:02 +0300 Subject: [PATCH 18/21] 8130525: Build fail on jdk9-client solaris-sparcv9 Reviewed-by: azvegint --- jdk/make/mapfiles/libawt/mapfile-mawt-vers | 1 - jdk/make/mapfiles/libawt_xawt/mapfile-vers | 1 - 2 files changed, 2 deletions(-) diff --git a/jdk/make/mapfiles/libawt/mapfile-mawt-vers b/jdk/make/mapfiles/libawt/mapfile-mawt-vers index 195ba1cbc50..8f9ee4135a5 100644 --- a/jdk/make/mapfiles/libawt/mapfile-mawt-vers +++ b/jdk/make/mapfiles/libawt/mapfile-mawt-vers @@ -196,7 +196,6 @@ SUNWprivate_1.1 { Java_sun_java2d_opengl_GLXGraphicsConfig_initConfig; Java_sun_java2d_opengl_GLXGraphicsConfig_getOGLCapabilities; Java_sun_java2d_opengl_GLXSurfaceData_initOps; - Java_sun_java2d_opengl_GLXSurfaceData_initPbuffer; Java_sun_print_CUPSPrinter_initIDs; Java_sun_print_CUPSPrinter_getCupsServer; diff --git a/jdk/make/mapfiles/libawt_xawt/mapfile-vers b/jdk/make/mapfiles/libawt_xawt/mapfile-vers index a2f75efcd0b..7e29cb3cb65 100644 --- a/jdk/make/mapfiles/libawt_xawt/mapfile-vers +++ b/jdk/make/mapfiles/libawt_xawt/mapfile-vers @@ -337,7 +337,6 @@ SUNWprivate_1.1 { Java_sun_java2d_opengl_GLXGraphicsConfig_initConfig; Java_sun_java2d_opengl_GLXGraphicsConfig_getOGLCapabilities; Java_sun_java2d_opengl_GLXSurfaceData_initOps; - Java_sun_java2d_opengl_GLXSurfaceData_initPbuffer; Java_sun_java2d_x11_X11PMBlitBgLoops_nativeBlitBg; Java_sun_java2d_x11_X11PMBlitLoops_nativeBlit; From dfbb82e3f9a3e87ca5649e5b1d9cdf3f9f2efb96 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 7 Jul 2015 09:51:30 +0300 Subject: [PATCH 19/21] 8081484: [TEST_BUG]Test javax/swing/plaf/basic/6866751/bug6866751.java fails Reviewed-by: alexsch, azvegint --- jdk/test/javax/swing/plaf/basic/6866751/bug6866751.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jdk/test/javax/swing/plaf/basic/6866751/bug6866751.java b/jdk/test/javax/swing/plaf/basic/6866751/bug6866751.java index 34da279a8b7..2f7c8aff410 100644 --- a/jdk/test/javax/swing/plaf/basic/6866751/bug6866751.java +++ b/jdk/test/javax/swing/plaf/basic/6866751/bug6866751.java @@ -27,6 +27,7 @@ @author Semyon Sadetsky */ import javax.swing.*; +import java.awt.*; public class bug6866751 { private static JFrame frame; @@ -54,8 +55,10 @@ public class bug6866751 { caretX + 1); } area.putClientProperty("caretWidth", 10); + frame.pack(); } }); + new Robot().waitForIdle(); SwingUtilities.invokeAndWait(new Runnable() { public void run() { int width = area.getWidth(); From 4b60e585076f09465b75e0d1feea559da6de59d1 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 7 Jul 2015 09:56:53 +0300 Subject: [PATCH 20/21] 8129940: JRadioButton does not honor non-standard FocusTraversalKeys Reviewed-by: alexsch, azvegint --- .../swing/plaf/basic/BasicRadioButtonUI.java | 34 +++-- .../FocusTraversal/FocusTraversal.java | 144 ++++++++++++++++++ 2 files changed, 166 insertions(+), 12 deletions(-) create mode 100644 jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java index 9c73734b72a..15fc03fd2dc 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * 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 @@ import sun.swing.SwingUtilities2; import sun.awt.AppContext; import java.util.Enumeration; import java.util.HashSet; +import java.util.Set; /** * RadioButtonUI implementation for BasicRadioButtonUI @@ -582,23 +583,32 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI */ private class KeyHandler implements KeyListener { - // This listener checks if the key event is a KeyEvent.VK_TAB - // or shift + KeyEvent.VK_TAB event on a radio button, consume the event - // if so and move the focus to next/previous component + // This listener checks if the key event is a focus traversal key event + // on a radio button, consume the event if so and move the focus + // to next/previous component public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_TAB) { - // Get the source of the event. - Object eventSrc = e.getSource(); - - // Check whether the source is a visible and enabled JRadioButton - if (isValidRadioButtonObj(eventSrc)) { + AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e); + if (stroke != null && e.getSource() instanceof JRadioButton) { + JRadioButton source = (JRadioButton) e.getSource(); + boolean next = isFocusTraversalKey(source, + KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + stroke); + if (next || isFocusTraversalKey(source, + KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + stroke)) { e.consume(); - ButtonGroupInfo btnGroupInfo = new ButtonGroupInfo((JRadioButton)eventSrc); - btnGroupInfo.jumpToNextComponent(!e.isShiftDown()); + ButtonGroupInfo btnGroupInfo = new ButtonGroupInfo(source); + btnGroupInfo.jumpToNextComponent(next); } } } + private boolean isFocusTraversalKey(JComponent c, int id, + AWTKeyStroke stroke) { + Set keys = c.getFocusTraversalKeys(id); + return keys != null && keys.contains(stroke); + } + public void keyReleased(KeyEvent e) { } diff --git a/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java b/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java new file mode 100644 index 00000000000..53e975447d4 --- /dev/null +++ b/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 8129940 + @summary JRadioButton does not honor non-standard FocusTraversalKeys + @author Semyon Sadetsky + */ + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.util.HashSet; +import java.util.Set; + +public class FocusTraversal { + + private static JFrame frame; + private static JRadioButton a; + private static JRadioButton d; + private static JTextField next; + private static JTextField prev; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame = new JFrame("FocusTraversalTest"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setUndecorated(true); + + Set keystrokes = new HashSet(); + keystrokes.add(KeyStroke.getKeyStroke("TAB")); + keystrokes.add(KeyStroke.getKeyStroke("ENTER")); + frame.setFocusTraversalKeys( + KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + keystrokes); + + a = new JRadioButton("a"); + JRadioButton b = new JRadioButton("b"); + JRadioButton c = new JRadioButton("c"); + d = new JRadioButton("d"); + + ButtonGroup radioButtonGroup = new ButtonGroup(); + radioButtonGroup.add(a); + radioButtonGroup.add(b); + radioButtonGroup.add(c); + radioButtonGroup.add(d); + + JPanel panel = new JPanel(); + prev = new JTextField("text"); + panel.add(prev); + panel.add(a); + panel.add(b); + panel.add(c); + panel.add(d); + next = new JTextField("text"); + panel.add(next); + + JPanel root = new JPanel(); + root.setLayout(new BorderLayout()); + root.add(panel, BorderLayout.CENTER); + root.add(new JButton("OK"), BorderLayout.SOUTH); + + frame.add(root); + frame.pack(); + frame.setVisible(true); + } + }); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + a.requestFocus(); + } + }); + + Robot robot = new Robot(); + robot.waitForIdle(); + + robot.setAutoDelay(200); + + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + Component focusOwner = + FocusManager.getCurrentManager().getFocusOwner(); + if (focusOwner != next) { + throw new RuntimeException( + "Focus component is wrong after forward key " + focusOwner); + } + } + }); + + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + Component focusOwner = + FocusManager.getCurrentManager().getFocusOwner(); + if (focusOwner != d) { + throw new RuntimeException( + "Focus component is wrong after backward key " + focusOwner); + } + } + }); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + frame.dispose(); + } + }); + System.out.println("ok"); + + } +} From 64b36f8f63616733af6ff35798bf95471fc97d26 Mon Sep 17 00:00:00 2001 From: Yuka Kamiya Date: Wed, 15 Jul 2015 11:05:51 +0900 Subject: [PATCH 21/21] 8032446: Support Unicode 7.0.0 in JDK 9 8130889: Missing "@since 1.8" tags in j.l.Character.java Reviewed-by: naoto, okutsu --- .../CharacterData00.java.template | 33 +- .../CharacterData01.java.template | 189 +- jdk/make/data/unicodedata/PropList.txt | 206 +- jdk/make/data/unicodedata/Scripts.txt | 447 +- jdk/make/data/unicodedata/SpecialCasing.txt | 52 +- jdk/make/data/unicodedata/UnicodeData.txt | 2875 ++++++++++- jdk/make/data/unicodedata/VERSION | 2 +- .../generatecharacter/GenerateCharacter.java | 10 +- .../tools/generatecharacter/UnicodeSpec.java | 22 +- .../share/classes/java/lang/Character.java | 3796 ++++++++++++-- .../share/classes/java/text/Bidi.java | 2 +- .../share/classes/java/text/Normalizer.java | 3 +- .../share/classes/sun/net/idn/StringPrep.java | 5 +- .../classes/sun/text/ComposedCharIter.java | 4 +- .../share/classes/sun/text/Normalizer.java | 6 +- .../share/classes/sun/text/bidi/BidiBase.java | 2344 +++++++-- .../share/classes/sun/text/bidi/BidiLine.java | 76 +- .../share/classes/sun/text/bidi/BidiRun.java | 4 +- .../classes/sun/text/bidi/BidiWriter.java | 452 ++ .../classes/sun/text/normalizer/BMPSet.java | 526 ++ .../classes/sun/text/normalizer/CharTrie.java | 206 +- .../normalizer/CharacterIteratorWrapper.java | 5 +- .../text/normalizer/FilteredNormalizer2.java | 266 + .../sun/text/normalizer/ICUBinary.java | 199 +- .../classes/sun/text/normalizer/ICUData.java | 83 - .../classes/sun/text/normalizer/IntTrie.java | 229 - .../sun/text/normalizer/Norm2AllModes.java | 287 ++ .../sun/text/normalizer/Normalizer2.java | 271 + .../sun/text/normalizer/NormalizerBase.java | 1470 ++---- .../text/normalizer/NormalizerDataReader.java | 389 -- .../sun/text/normalizer/NormalizerImpl.java | 4415 +++++++---------- .../{UnicodeMatcher.java => OutputInt.java} | 37 +- .../text/normalizer/RangeValueIterator.java | 141 - .../sun/text/normalizer/Replaceable.java | 5 +- .../text/normalizer/ReplaceableString.java | 19 +- .../ReplaceableUCharacterIterator.java | 6 +- .../normalizer/RuleCharacterIterator.java | 371 -- .../sun/text/normalizer/SymbolTable.java | 124 - .../classes/sun/text/normalizer/Trie.java | 183 +- .../classes/sun/text/normalizer/Trie2.java | 655 +++ .../classes/sun/text/normalizer/Trie2_16.java | 167 + .../sun/text/normalizer/TrieIterator.java | 547 -- .../sun/text/normalizer/UBiDiProps.java | 244 +- .../sun/text/normalizer/UCharacter.java | 480 +- .../text/normalizer/UCharacterIterator.java | 105 +- .../text/normalizer/UCharacterProperty.java | 580 ++- .../normalizer/UCharacterPropertyReader.java | 190 - .../classes/sun/text/normalizer/UTF16.java | 212 +- .../sun/text/normalizer/UnicodeSet.java | 1478 ++---- .../text/normalizer/UnicodeSetIterator.java | 219 - .../text/normalizer/UnicodeSetStringSpan.java | 1165 +++++ .../classes/sun/text/normalizer/Utility.java | 218 +- .../share/classes/sun/text/resources/nfc.icu | Bin 0 -> 34464 bytes .../share/classes/sun/text/resources/nfkc.icu | Bin 0 -> 53504 bytes .../classes/sun/text/resources/nfkc_cf.icu | Bin 0 -> 50288 bytes .../classes/sun/text/resources/ubidi.icu | Bin 19924 -> 22976 bytes .../classes/sun/text/resources/unorm.icu | Bin 126672 -> 0 bytes .../classes/sun/text/resources/uprops.icu | Bin 92804 -> 113360 bytes .../classes/java/awt/font/NumericShaper.java | 489 +- .../awt/font/NumericShaper/ShapingTest.java | 17 +- jdk/test/java/lang/Character/CheckProp.java | 4 +- jdk/test/java/lang/Character/CheckScript.java | 5 +- jdk/test/java/lang/Character/PropList.txt | 206 +- .../lang/Character/PropertyValueAliases.txt | 144 +- jdk/test/java/lang/Character/Scripts.txt | 447 +- jdk/test/java/text/Bidi/BidiConformance.java | 209 +- .../java/text/BreakIterator/Bug8032446.java | 56 + jdk/test/sun/net/idn/NFS4StringPrep.java | 3 +- 68 files changed, 17910 insertions(+), 9690 deletions(-) create mode 100644 jdk/src/java.base/share/classes/sun/text/bidi/BidiWriter.java create mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/BMPSet.java create mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/FilteredNormalizer2.java delete mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/ICUData.java delete mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/IntTrie.java create mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/Norm2AllModes.java create mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/Normalizer2.java delete mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerDataReader.java rename jdk/src/java.base/share/classes/sun/text/normalizer/{UnicodeMatcher.java => OutputInt.java} (53%) delete mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/RangeValueIterator.java delete mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/RuleCharacterIterator.java delete mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/SymbolTable.java create mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/Trie2.java create mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/Trie2_16.java delete mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/TrieIterator.java delete mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterPropertyReader.java delete mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSetIterator.java create mode 100644 jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSetStringSpan.java create mode 100644 jdk/src/java.base/share/classes/sun/text/resources/nfc.icu create mode 100644 jdk/src/java.base/share/classes/sun/text/resources/nfkc.icu create mode 100644 jdk/src/java.base/share/classes/sun/text/resources/nfkc_cf.icu delete mode 100644 jdk/src/java.base/share/classes/sun/text/resources/unorm.icu create mode 100644 jdk/test/java/text/BreakIterator/Bug8032446.java diff --git a/jdk/make/data/characterdata/CharacterData00.java.template b/jdk/make/data/characterdata/CharacterData00.java.template index 1045515b42d..42473074cb0 100644 --- a/jdk/make/data/characterdata/CharacterData00.java.template +++ b/jdk/make/data/characterdata/CharacterData00.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -226,6 +226,11 @@ class CharacterData00 extends CharacterData { case 0xA77D : mapChar = 0x1D79; break; case 0xA78D : mapChar = 0x0265; break; case 0xA7AA : mapChar = 0x0266; break; + case 0xA7AB : mapChar = 0x025C; break; + case 0xA7AC : mapChar = 0x0261; break; + case 0xA7AD : mapChar = 0x026C; break; + case 0xA7B0 : mapChar = 0x029E; break; + case 0xA7B1 : mapChar = 0x0287; break; // default mapChar is already set, so no // need to redo it here. // default : mapChar = ch; @@ -284,10 +289,15 @@ class CharacterData00 extends CharacterData { case 0x0250 : mapChar = 0x2C6F; break; case 0x0251 : mapChar = 0x2C6D; break; case 0x0252 : mapChar = 0x2C70; break; + case 0x025C : mapChar = 0xA7AB; break; + case 0x0261 : mapChar = 0xA7AC; break; case 0x0265 : mapChar = 0xA78D; break; case 0x0266 : mapChar = 0xA7AA; break; case 0x026B : mapChar = 0x2C62; break; + case 0x026C : mapChar = 0xA7AD; break; case 0x0271 : mapChar = 0x2C6E; break; + case 0x0287 : mapChar = 0xA7B1; break; + case 0x029E : mapChar = 0xA7B0; break; case 0x027D : mapChar = 0x2C64; break; case 0x1D79 : mapChar = 0xA77D; break; case 0x1D7D : mapChar = 0x2C63; break; @@ -503,6 +513,22 @@ class CharacterData00 extends CharacterData { // This is the only char with RLO directionality = Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE; break; + case 0x2066 : + // This is the only char with LRI + directionality = Character.DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE; + break; + case 0x2067 : + // This is the only char with RLI + directionality = Character.DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE; + break; + case 0x2068 : + // This is the only char with FSI + directionality = Character.DIRECTIONALITY_FIRST_STRONG_ISOLATE; + break; + case 0x2069 : + // This is the only char with PDI + directionality = Character.DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE; + break; default : directionality = Character.DIRECTIONALITY_UNDEFINED; break; @@ -537,11 +563,16 @@ class CharacterData00 extends CharacterData { case 0x0250 : mapChar = 0x2C6F; break; case 0x0251 : mapChar = 0x2C6D; break; case 0x0252 : mapChar = 0x2C70; break; + case 0x025C : mapChar = 0xA7AB; break; + case 0x0261 : mapChar = 0xA7AC; break; case 0x0265 : mapChar = 0xA78D; break; case 0x0266 : mapChar = 0xA7AA; break; case 0x026B : mapChar = 0x2C62; break; + case 0x026C : mapChar = 0xA7AD; break; case 0x0271 : mapChar = 0x2C6E; break; case 0x027D : mapChar = 0x2C64; break; + case 0x0287 : mapChar = 0xA7B1; break; + case 0x029E : mapChar = 0xA7B0; break; case 0x1D79 : mapChar = 0xA77D; break; case 0x1D7D : mapChar = 0x2C63; break; case 0x2C65 : mapChar = 0x023A; break; diff --git a/jdk/make/data/characterdata/CharacterData01.java.template b/jdk/make/data/characterdata/CharacterData01.java.template index 3bfe26f691e..78bf83874d9 100644 --- a/jdk/make/data/characterdata/CharacterData01.java.template +++ b/jdk/make/data/characterdata/CharacterData01.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,81 +244,118 @@ class CharacterData01 extends CharacterData { case 0x10132: retval = 80000; break; // AEGEAN NUMBER EIGHTY THOUSAND case 0x10133: retval = 90000; break; // AEGEAN NUMBER NINETY THOUSAND case 0x10323: retval = 50; break; // OLD ITALIC NUMERAL FIFTY - - case 0x010144: retval = 50; break; // ACROPHONIC ATTIC FIFTY - case 0x010145: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED - case 0x010146: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND - case 0x010147: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND - case 0x01014A: retval = 50; break; // ACROPHONIC ATTIC FIFTY TALENTS - case 0x01014B: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED TALENTS - case 0x01014C: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED TALENTS - case 0x01014D: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND TALENTS - case 0x01014E: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND TALENTS - case 0x010151: retval = 50; break; // ACROPHONIC ATTIC FIFTY STATERS - case 0x010152: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED STATERS - case 0x010153: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED STATERS - case 0x010154: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND STATERS - case 0x010155: retval = 10000; break; // ACROPHONIC ATTIC TEN THOUSAND STATERS - case 0x010156: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND STATERS - case 0x010166: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY - case 0x010167: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM - case 0x010168: retval = 50; break; // ACROPHONIC HERMIONIAN FIFTY - case 0x010169: retval = 50; break; // ACROPHONIC THESPIAN FIFTY - case 0x01016A: retval = 100; break; // ACROPHONIC THESPIAN ONE HUNDRED - case 0x01016B: retval = 300; break; // ACROPHONIC THESPIAN THREE HUNDRED - case 0x01016C: retval = 500; break; // ACROPHONIC EPIDAUREAN FIVE HUNDRED - case 0x01016D: retval = 500; break; // ACROPHONIC TROEZENIAN FIVE HUNDRED - case 0x01016E: retval = 500; break; // ACROPHONIC THESPIAN FIVE HUNDRED - case 0x01016F: retval = 500; break; // ACROPHONIC CARYSTIAN FIVE HUNDRED - case 0x010170: retval = 500; break; // ACROPHONIC NAXIAN FIVE HUNDRED - case 0x010171: retval = 1000; break; // ACROPHONIC THESPIAN ONE THOUSAND - case 0x010172: retval = 5000; break; // ACROPHONIC THESPIAN FIVE THOUSAND - case 0x010174: retval = 50; break; // ACROPHONIC STRATIAN FIFTY MNAS - case 0x010341: retval = 90; break; // GOTHIC LETTER NINETY - case 0x01034A: retval = 900; break; // GOTHIC LETTER NINE HUNDRED - case 0x0103D5: retval = 100; break; // OLD PERSIAN NUMBER HUNDRED - case 0x01085D: retval = 100; break; // IMPERIAL ARAMAIC NUMBER ONE HUNDRED - case 0x01085E: retval = 1000; break; // IMPERIAL ARAMAIC NUMBER ONE THOUSAND - case 0x01085F: retval = 10000; break; // IMPERIAL ARAMAIC NUMBER TEN THOUSAND - case 0x010919: retval = 100; break; // PHOENICIAN NUMBER ONE HUNDRED - case 0x010A46: retval = 100; break; // KHAROSHTHI NUMBER ONE HUNDRED - case 0x010A47: retval = 1000; break; // KHAROSHTHI NUMBER ONE THOUSAND - case 0x010A7E: retval = 50; break; // OLD SOUTH ARABIAN NUMBER FIFTY - case 0x010B5E: retval = 100; break; // INSCRIPTIONAL PARTHIAN NUMBER ONE HUNDRED - case 0x010B5F: retval = 1000; break; // INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND - case 0x010B7E: retval = 100; break; // INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED - case 0x010B7F: retval = 1000; break; // INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND - case 0x010E6C: retval = 40; break; // RUMI NUMBER FORTY - case 0x010E6D: retval = 50; break; // RUMI NUMBER FIFTY - case 0x010E6E: retval = 60; break; // RUMI NUMBER SIXTY - case 0x010E6F: retval = 70; break; // RUMI NUMBER SEVENTY - case 0x010E70: retval = 80; break; // RUMI NUMBER EIGHTY - case 0x010E71: retval = 90; break; // RUMI NUMBER NINETY - case 0x010E72: retval = 100; break; // RUMI NUMBER ONE HUNDRED - case 0x010E73: retval = 200; break; // RUMI NUMBER TWO HUNDRED - case 0x010E74: retval = 300; break; // RUMI NUMBER THREE HUNDRED - case 0x010E75: retval = 400; break; // RUMI NUMBER FOUR HUNDRED - case 0x010E76: retval = 500; break; // RUMI NUMBER FIVE HUNDRED - case 0x010E77: retval = 600; break; // RUMI NUMBER SIX HUNDRED - case 0x010E78: retval = 700; break; // RUMI NUMBER SEVEN HUNDRED - case 0x010E79: retval = 800; break; // RUMI NUMBER EIGHT HUNDRED - case 0x010E7A: retval = 900; break; // RUMI NUMBER NINE HUNDRED - case 0x01105E: retval = 40; break; // BRAHMI NUMBER FORTY - case 0x01105F: retval = 50; break; // BRAHMI NUMBER FIFTY - case 0x011060: retval = 60; break; // BRAHMI NUMBER SIXTY - case 0x011061: retval = 70; break; // BRAHMI NUMBER SEVENTY - case 0x011062: retval = 80; break; // BRAHMI NUMBER EIGHTY - case 0x011063: retval = 90; break; // BRAHMI NUMBER NINETY - case 0x011064: retval = 100; break; // BRAHMI NUMBER ONE HUNDRED - case 0x011065: retval = 1000; break; // BRAHMI NUMBER ONE THOUSAND - case 0x012432: retval = 216000; break; // CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH - case 0x012433: retval = 432000; break; // CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN - case 0x01D36C: retval = 40; break; // COUNTING ROD TENS DIGIT FOUR - case 0x01D36D: retval = 50; break; // COUNTING ROD TENS DIGIT FIVE - case 0x01D36E: retval = 60; break; // COUNTING ROD TENS DIGIT SIX - case 0x01D36F: retval = 70; break; // COUNTING ROD TENS DIGIT SEVEN - case 0x01D370: retval = 80; break; // COUNTING ROD TENS DIGIT EIGHT - case 0x01D371: retval = 90; break; // COUNTING ROD TENS DIGIT NINE + case 0x10144: retval = 50; break; // ACROPHONIC ATTIC FIFTY + case 0x10145: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED + case 0x10146: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND + case 0x10147: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND + case 0x1014A: retval = 50; break; // ACROPHONIC ATTIC FIFTY TALENTS + case 0x1014B: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED TALENTS + case 0x1014C: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED TALENTS + case 0x1014D: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND TALENTS + case 0x1014E: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND TALENTS + case 0x10151: retval = 50; break; // ACROPHONIC ATTIC FIFTY STATERS + case 0x10152: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED STATERS + case 0x10153: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED STATERS + case 0x10154: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND STATERS + case 0x10155: retval = 10000; break; // ACROPHONIC ATTIC TEN THOUSAND STATERS + case 0x10156: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND STATERS + case 0x10166: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY + case 0x10167: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM + case 0x10168: retval = 50; break; // ACROPHONIC HERMIONIAN FIFTY + case 0x10169: retval = 50; break; // ACROPHONIC THESPIAN FIFTY + case 0x1016A: retval = 100; break; // ACROPHONIC THESPIAN ONE HUNDRED + case 0x1016B: retval = 300; break; // ACROPHONIC THESPIAN THREE HUNDRED + case 0x1016C: retval = 500; break; // ACROPHONIC EPIDAUREAN FIVE HUNDRED + case 0x1016D: retval = 500; break; // ACROPHONIC TROEZENIAN FIVE HUNDRED + case 0x1016E: retval = 500; break; // ACROPHONIC THESPIAN FIVE HUNDRED + case 0x1016F: retval = 500; break; // ACROPHONIC CARYSTIAN FIVE HUNDRED + case 0x10170: retval = 500; break; // ACROPHONIC NAXIAN FIVE HUNDRED + case 0x10171: retval = 1000; break; // ACROPHONIC THESPIAN ONE THOUSAND + case 0x10172: retval = 5000; break; // ACROPHONIC THESPIAN FIVE THOUSAND + case 0x10174: retval = 50; break; // ACROPHONIC STRATIAN FIFTY MNAS + case 0x102ED: retval = 40; break; // COPTIC EPACT NUMBER FORTY + case 0x102EE: retval = 50; break; // COPTIC EPACT NUMBER FIFTY + case 0x102EF: retval = 60; break; // COPTIC EPACT NUMBER SIXTY + case 0x102F0: retval = 70; break; // COPTIC EPACT NUMBER SEVENTY + case 0x102F1: retval = 80; break; // COPTIC EPACT NUMBER EIGHTY + case 0x102F2: retval = 90; break; // COPTIC EPACT NUMBER NINETY + case 0x102F3: retval = 100; break; // COPTIC EPACT NUMBER ONE HUNDRED + case 0x102F4: retval = 200; break; // COPTIC EPACT NUMBER TWO HUNDRED + case 0x102F5: retval = 300; break; // COPTIC EPACT NUMBER THREE HUNDRED + case 0x102F6: retval = 400; break; // COPTIC EPACT NUMBER FOUR HUNDRED + case 0x102F7: retval = 500; break; // COPTIC EPACT NUMBER FIVE HUNDRED + case 0x102F8: retval = 600; break; // COPTIC EPACT NUMBER SIX HUNDRED + case 0x102F9: retval = 700; break; // COPTIC EPACT NUMBER SEVEN HUNDRED + case 0x102FA: retval = 800; break; // COPTIC EPACT NUMBER EIGHT HUNDRED + case 0x102FB: retval = 900; break; // COPTIC EPACT NUMBER NINE HUNDRED + case 0x10341: retval = 90; break; // GOTHIC LETTER NINETY + case 0x1034A: retval = 900; break; // GOTHIC LETTER NINE HUNDRED + case 0x103D5: retval = 100; break; // OLD PERSIAN NUMBER HUNDRED + case 0x1085D: retval = 100; break; // IMPERIAL ARAMAIC NUMBER ONE HUNDRED + case 0x1085E: retval = 1000; break; // IMPERIAL ARAMAIC NUMBER ONE THOUSAND + case 0x1085F: retval = 10000; break; // IMPERIAL ARAMAIC NUMBER TEN THOUSAND + case 0x108AF: retval = 100; break; // NABATAEAN NUMBER ONE HUNDRED + case 0x10919: retval = 100; break; // PHOENICIAN NUMBER ONE HUNDRED + case 0x10A46: retval = 100; break; // KHAROSHTHI NUMBER ONE HUNDRED + case 0x10A47: retval = 1000; break; // KHAROSHTHI NUMBER ONE THOUSAND + case 0x10A7E: retval = 50; break; // OLD SOUTH ARABIAN NUMBER FIFTY + case 0x10AEF: retval = 100; break; // MANICHAEAN NUMBER ONE HUNDRED + case 0x10B5E: retval = 100; break; // INSCRIPTIONAL PARTHIAN NUMBER ONE HUNDRED + case 0x10B5F: retval = 1000; break; // INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND + case 0x10B7E: retval = 100; break; // INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED + case 0x10B7F: retval = 1000; break; // INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND + case 0x10BAF: retval = 100; break; // PSALTER PAHLAVI NUMBER ONE HUNDRED + case 0x10E6C: retval = 40; break; // RUMI NUMBER FORTY + case 0x10E6D: retval = 50; break; // RUMI NUMBER FIFTY + case 0x10E6E: retval = 60; break; // RUMI NUMBER SIXTY + case 0x10E6F: retval = 70; break; // RUMI NUMBER SEVENTY + case 0x10E70: retval = 80; break; // RUMI NUMBER EIGHTY + case 0x10E71: retval = 90; break; // RUMI NUMBER NINETY + case 0x10E72: retval = 100; break; // RUMI NUMBER ONE HUNDRED + case 0x10E73: retval = 200; break; // RUMI NUMBER TWO HUNDRED + case 0x10E74: retval = 300; break; // RUMI NUMBER THREE HUNDRED + case 0x10E75: retval = 400; break; // RUMI NUMBER FOUR HUNDRED + case 0x10E76: retval = 500; break; // RUMI NUMBER FIVE HUNDRED + case 0x10E77: retval = 600; break; // RUMI NUMBER SIX HUNDRED + case 0x10E78: retval = 700; break; // RUMI NUMBER SEVEN HUNDRED + case 0x10E79: retval = 800; break; // RUMI NUMBER EIGHT HUNDRED + case 0x10E7A: retval = 900; break; // RUMI NUMBER NINE HUNDRED + case 0x1105E: retval = 40; break; // BRAHMI NUMBER FORTY + case 0x1105F: retval = 50; break; // BRAHMI NUMBER FIFTY + case 0x11060: retval = 60; break; // BRAHMI NUMBER SIXTY + case 0x11061: retval = 70; break; // BRAHMI NUMBER SEVENTY + case 0x11062: retval = 80; break; // BRAHMI NUMBER EIGHTY + case 0x11063: retval = 90; break; // BRAHMI NUMBER NINETY + case 0x11064: retval = 100; break; // BRAHMI NUMBER ONE HUNDRED + case 0x11065: retval = 1000; break; // BRAHMI NUMBER ONE THOUSAND + case 0x111ED: retval = 40; break; // SINHALA ARCHAIC NUMBER FORTY + case 0x111EE: retval = 50; break; // SINHALA ARCHAIC NUMBER FIFTY + case 0x111EF: retval = 60; break; // SINHALA ARCHAIC NUMBER SIXTY + case 0x111F0: retval = 70; break; // SINHALA ARCHAIC NUMBER SEVENTY + case 0x111F1: retval = 80; break; // SINHALA ARCHAIC NUMBER EIGHTY + case 0x111F2: retval = 90; break; // SINHALA ARCHAIC NUMBER NINETY + case 0x111F3: retval = 100; break; // SINHALA ARCHAIC NUMBER ONE HUNDRED + case 0x111F4: retval = 1000; break; // SINHALA ARCHAIC NUMBER ONE THOUSAND + case 0x118ED: retval = 40; break; // WARANG CITI NUMBER FORTY + case 0x118EE: retval = 50; break; // WARANG CITI NUMBER FIFTY + case 0x118EF: retval = 60; break; // WARANG CITI NUMBER SIXTY + case 0x118F0: retval = 70; break; // WARANG CITI NUMBER SEVENTY + case 0x118F1: retval = 80; break; // WARANG CITI NUMBER EIGHTY + case 0x118F2: retval = 90; break; // WARANG CITI NUMBER NINETY + case 0x12432: retval = 216000; break; // CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH + case 0x12433: retval = 432000; break; // CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN + case 0x12467: retval = 40; break; // CUNEIFORM NUMERIC SIGN ELAMITE FORTY + case 0x12468: retval = 50; break; // CUNEIFORM NUMERIC SIGN ELAMITE FIFTY + case 0x16B5C: retval = 100; break; // PAHAWH HMONG NUMBER HUNDREDS + case 0x16B5D: retval = 10000; break; // PAHAWH HMONG NUMBER TEN THOUSANDS + case 0x16B5E: retval = 1000000; break; // PAHAWH HMONG NUMBER MILLIONS + case 0x16B5F: retval = 100000000; break;// PAHAWH HMONG NUMBER HUNDRED MILLIONS + case 0x1D36C: retval = 40; break; // COUNTING ROD TENS DIGIT FOUR + case 0x1D36D: retval = 50; break; // COUNTING ROD TENS DIGIT FIVE + case 0x1D36E: retval = 60; break; // COUNTING ROD TENS DIGIT SIX + case 0x1D36F: retval = 70; break; // COUNTING ROD TENS DIGIT SEVEN + case 0x1D370: retval = 80; break; // COUNTING ROD TENS DIGIT EIGHT + case 0x1D371: retval = 90; break; // COUNTING ROD TENS DIGIT NINE default: retval = -2; break; } diff --git a/jdk/make/data/unicodedata/PropList.txt b/jdk/make/data/unicodedata/PropList.txt index 9ce7eec9713..82f650d5749 100644 --- a/jdk/make/data/unicodedata/PropList.txt +++ b/jdk/make/data/unicodedata/PropList.txt @@ -1,8 +1,8 @@ -# PropList-6.2.0.txt -# Date: 2012-05-23, 20:34:59 GMT [MD] +# PropList-7.0.0.txt +# Date: 2014-02-19, 15:51:26 GMT [MD] # # Unicode Character Database -# Copyright (c) 1991-2012 Unicode, Inc. +# Copyright (c) 1991-2014 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # For documentation, see http://www.unicode.org/reports/tr44/ @@ -13,7 +13,6 @@ 0085 ; White_Space # Cc 00A0 ; White_Space # Zs NO-BREAK SPACE 1680 ; White_Space # Zs OGHAM SPACE MARK -180E ; White_Space # Zs MONGOLIAN VOWEL SEPARATOR 2000..200A ; White_Space # Zs [11] EN QUAD..HAIR SPACE 2028 ; White_Space # Zl LINE SEPARATOR 2029 ; White_Space # Zp PARAGRAPH SEPARATOR @@ -21,14 +20,16 @@ 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE 3000 ; White_Space # Zs IDEOGRAPHIC SPACE -# Total code points: 26 +# Total code points: 25 # ================================================ +061C ; Bidi_Control # Cf ARABIC LETTER MARK 200E..200F ; Bidi_Control # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK 202A..202E ; Bidi_Control # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE +2066..2069 ; Bidi_Control # Cf [4] LEFT-TO-RIGHT ISOLATE..POP DIRECTIONAL ISOLATE -# Total code points: 7 +# Total code points: 12 # ================================================ @@ -51,6 +52,7 @@ 2E17 ; Dash # Pd DOUBLE OBLIQUE HYPHEN 2E1A ; Dash # Pd HYPHEN WITH DIAERESIS 2E3A..2E3B ; Dash # Pd [2] TWO-EM DASH..THREE-EM DASH +2E40 ; Dash # Pd DOUBLE HYPHEN 301C ; Dash # Pd WAVE DASH 3030 ; Dash # Pd WAVY DASH 30A0 ; Dash # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN @@ -59,7 +61,7 @@ FE58 ; Dash # Pd SMALL EM DASH FE63 ; Dash # Pd SMALL HYPHEN-MINUS FF0D ; Dash # Pd FULLWIDTH HYPHEN-MINUS -# Total code points: 27 +# Total code points: 28 # ================================================ @@ -91,6 +93,7 @@ FF65 ; Hyphen # Po HALFWIDTH KATAKANA MIDDLE DOT 201F ; Quotation_Mark # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK 2039 ; Quotation_Mark # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK 203A ; Quotation_Mark # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +2E42 ; Quotation_Mark # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK 300C ; Quotation_Mark # Ps LEFT CORNER BRACKET 300D ; Quotation_Mark # Pe RIGHT CORNER BRACKET 300E ; Quotation_Mark # Ps LEFT WHITE CORNER BRACKET @@ -106,7 +109,7 @@ FF07 ; Quotation_Mark # Po FULLWIDTH APOSTROPHE FF62 ; Quotation_Mark # Ps HALFWIDTH LEFT CORNER BRACKET FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET -# Total code points: 29 +# Total code points: 30 # ================================================ @@ -136,6 +139,7 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET 1361..1368 ; Terminal_Punctuation # Po [8] ETHIOPIC WORDSPACE..ETHIOPIC PARAGRAPH SEPARATOR 166D..166E ; Terminal_Punctuation # Po [2] CANADIAN SYLLABICS CHI SIGN..CANADIAN SYLLABICS FULL STOP 16EB..16ED ; Terminal_Punctuation # Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION +1735..1736 ; Terminal_Punctuation # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION 17D4..17D6 ; Terminal_Punctuation # Po [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH 17DA ; Terminal_Punctuation # Po KHMER SIGN KOOMUUT 1802..1805 ; Terminal_Punctuation # Po [4] MONGOLIAN COMMA..MONGOLIAN FOUR DOTS @@ -149,6 +153,8 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET 203C..203D ; Terminal_Punctuation # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG 2047..2049 ; Terminal_Punctuation # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK 2E2E ; Terminal_Punctuation # Po REVERSED QUESTION MARK +2E3C ; Terminal_Punctuation # Po STENOGRAPHIC FULL STOP +2E41 ; Terminal_Punctuation # Po REVERSED COMMA 3001..3002 ; Terminal_Punctuation # Po [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP A4FE..A4FF ; Terminal_Punctuation # Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP A60D..A60F ; Terminal_Punctuation # Po [3] VAI COMMA..VAI QUESTION MARK @@ -174,14 +180,27 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA 103D0 ; Terminal_Punctuation # Po OLD PERSIAN WORD DIVIDER 10857 ; Terminal_Punctuation # Po IMPERIAL ARAMAIC SECTION SIGN 1091F ; Terminal_Punctuation # Po PHOENICIAN WORD SEPARATOR +10A56..10A57 ; Terminal_Punctuation # Po [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA +10AF0..10AF5 ; Terminal_Punctuation # Po [6] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION TWO DOTS 10B3A..10B3F ; Terminal_Punctuation # Po [6] TINY TWO DOTS OVER ONE DOT PUNCTUATION..LARGE ONE RING OVER TWO RINGS PUNCTUATION +10B99..10B9C ; Terminal_Punctuation # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT 11047..1104D ; Terminal_Punctuation # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS 110BE..110C1 ; Terminal_Punctuation # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA 11141..11143 ; Terminal_Punctuation # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK 111C5..111C6 ; Terminal_Punctuation # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA -12470..12473 ; Terminal_Punctuation # Po [4] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON +111CD ; Terminal_Punctuation # Po SHARADA SUTRA MARK +11238..1123C ; Terminal_Punctuation # Po [5] KHOJKI DANDA..KHOJKI DOUBLE SECTION MARK +115C2..115C5 ; Terminal_Punctuation # Po [4] SIDDHAM DANDA..SIDDHAM SEPARATOR BAR +115C9 ; Terminal_Punctuation # Po SIDDHAM END OF TEXT MARK +11641..11642 ; Terminal_Punctuation # Po [2] MODI DANDA..MODI DOUBLE DANDA +12470..12474 ; Terminal_Punctuation # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON +16A6E..16A6F ; Terminal_Punctuation # Po [2] MRO DANDA..MRO DOUBLE DANDA +16AF5 ; Terminal_Punctuation # Po BASSA VAH FULL STOP +16B37..16B39 ; Terminal_Punctuation # Po [3] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN CIM CHEEM +16B44 ; Terminal_Punctuation # Po PAHAWH HMONG SIGN XAUS +1BC9F ; Terminal_Punctuation # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP -# Total code points: 176 +# Total code points: 214 # ================================================ @@ -230,6 +249,10 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA 21D5..21DB ; Other_Math # So [7] UP DOWN DOUBLE ARROW..RIGHTWARDS TRIPLE ARROW 21DD ; Other_Math # So RIGHTWARDS SQUIGGLE ARROW 21E4..21E5 ; Other_Math # So [2] LEFTWARDS ARROW TO BAR..RIGHTWARDS ARROW TO BAR +2308 ; Other_Math # Ps LEFT CEILING +2309 ; Other_Math # Pe RIGHT CEILING +230A ; Other_Math # Ps LEFT FLOOR +230B ; Other_Math # Pe RIGHT FLOOR 23B4..23B5 ; Other_Math # So [2] TOP SQUARE BRACKET..BOTTOM SQUARE BRACKET 23B7 ; Other_Math # So RADICAL SYMBOL BOTTOM 23D0 ; Other_Math # So VERTICAL LINE EXTENSION @@ -358,7 +381,7 @@ FF3E ; Other_Math # Sk FULLWIDTH CIRCUMFLEX ACCENT 1EEA5..1EEA9 ; Other_Math # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH 1EEAB..1EEBB ; Other_Math # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN -# Total code points: 1358 +# Total code points: 1362 # ================================================ @@ -403,8 +426,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0825..0827 ; Other_Alphabetic # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082C ; Other_Alphabetic # Mn [4] SAMARITAN VOWEL SIGN LONG I..SAMARITAN VOWEL SIGN SUKUN 08E4..08E9 ; Other_Alphabetic # Mn [6] ARABIC CURLY FATHA..ARABIC CURLY KASRATAN -08F0..08FE ; Other_Alphabetic # Mn [15] ARABIC OPEN FATHATAN..ARABIC DAMMA WITH DOT -0900..0902 ; Other_Alphabetic # Mn [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA +08F0..0902 ; Other_Alphabetic # Mn [19] ARABIC OPEN FATHATAN..DEVANAGARI SIGN ANUSVARA 0903 ; Other_Alphabetic # Mc DEVANAGARI SIGN VISARGA 093A ; Other_Alphabetic # Mn DEVANAGARI VOWEL SIGN OE 093B ; Other_Alphabetic # Mc DEVANAGARI VOWEL SIGN OOE @@ -457,6 +479,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0BC6..0BC8 ; Other_Alphabetic # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI 0BCA..0BCC ; Other_Alphabetic # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU 0BD7 ; Other_Alphabetic # Mc TAMIL AU LENGTH MARK +0C00 ; Other_Alphabetic # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE 0C01..0C03 ; Other_Alphabetic # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA 0C3E..0C40 ; Other_Alphabetic # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II 0C41..0C44 ; Other_Alphabetic # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR @@ -464,6 +487,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0C4A..0C4C ; Other_Alphabetic # Mn [3] TELUGU VOWEL SIGN O..TELUGU VOWEL SIGN AU 0C55..0C56 ; Other_Alphabetic # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK 0C62..0C63 ; Other_Alphabetic # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL +0C81 ; Other_Alphabetic # Mn KANNADA SIGN CANDRABINDU 0C82..0C83 ; Other_Alphabetic # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 0CBE ; Other_Alphabetic # Mc KANNADA VOWEL SIGN AA 0CBF ; Other_Alphabetic # Mn KANNADA VOWEL SIGN I @@ -474,6 +498,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0CCC ; Other_Alphabetic # Mn KANNADA VOWEL SIGN AU 0CD5..0CD6 ; Other_Alphabetic # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK 0CE2..0CE3 ; Other_Alphabetic # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL +0D01 ; Other_Alphabetic # Mn MALAYALAM SIGN CANDRABINDU 0D02..0D03 ; Other_Alphabetic # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D3E..0D40 ; Other_Alphabetic # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II 0D41..0D44 ; Other_Alphabetic # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR @@ -538,7 +563,8 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 19B0..19C0 ; Other_Alphabetic # Mc [17] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE VOWEL SIGN IY 19C8..19C9 ; Other_Alphabetic # Mc [2] NEW TAI LUE TONE MARK-1..NEW TAI LUE TONE MARK-2 1A17..1A18 ; Other_Alphabetic # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U -1A19..1A1B ; Other_Alphabetic # Mc [3] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN AE +1A19..1A1A ; Other_Alphabetic # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O +1A1B ; Other_Alphabetic # Mn BUGINESE VOWEL SIGN AE 1A55 ; Other_Alphabetic # Mc TAI THAM CONSONANT SIGN MEDIAL RA 1A56 ; Other_Alphabetic # Mn TAI THAM CONSONANT SIGN MEDIAL LA 1A57 ; Other_Alphabetic # Mc TAI THAM CONSONANT SIGN LA TANG LAI @@ -564,7 +590,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 1BA2..1BA5 ; Other_Alphabetic # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU 1BA6..1BA7 ; Other_Alphabetic # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG 1BA8..1BA9 ; Other_Alphabetic # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG -1BAC..1BAD ; Other_Alphabetic # Mc [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA +1BAC..1BAD ; Other_Alphabetic # Mn [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA 1BE7 ; Other_Alphabetic # Mc BATAK VOWEL SIGN E 1BE8..1BE9 ; Other_Alphabetic # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE 1BEA..1BEC ; Other_Alphabetic # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O @@ -575,6 +601,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 1C2C..1C33 ; Other_Alphabetic # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T 1C34..1C35 ; Other_Alphabetic # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG 1CF2..1CF3 ; Other_Alphabetic # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA +1DE7..1DF4 ; Other_Alphabetic # Mn [14] COMBINING LATIN SMALL LETTER ALPHA..COMBINING LATIN SMALL LETTER U WITH DIAERESIS 24B6..24E9 ; Other_Alphabetic # So [52] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN SMALL LETTER Z 2DE0..2DFF ; Other_Alphabetic # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS A674..A67B ; Other_Alphabetic # Mn [8] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC LETTER OMEGA @@ -616,6 +643,7 @@ ABE6..ABE7 ; Other_Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETE ABE8 ; Other_Alphabetic # Mn MEETEI MAYEK VOWEL SIGN UNAP ABE9..ABEA ; Other_Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA +10376..1037A ; Other_Alphabetic # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII 10A01..10A03 ; Other_Alphabetic # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R 10A05..10A06 ; Other_Alphabetic # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O 10A0C..10A0F ; Other_Alphabetic # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA @@ -636,14 +664,54 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 111B3..111B5 ; Other_Alphabetic # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II 111B6..111BE ; Other_Alphabetic # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O 111BF ; Other_Alphabetic # Mc SHARADA VOWEL SIGN AU +1122C..1122E ; Other_Alphabetic # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II +1122F..11231 ; Other_Alphabetic # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI +11232..11233 ; Other_Alphabetic # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU +11234 ; Other_Alphabetic # Mn KHOJKI SIGN ANUSVARA +11237 ; Other_Alphabetic # Mn KHOJKI SIGN SHADDA +112DF ; Other_Alphabetic # Mn KHUDAWADI SIGN ANUSVARA +112E0..112E2 ; Other_Alphabetic # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II +112E3..112E8 ; Other_Alphabetic # Mn [6] KHUDAWADI VOWEL SIGN U..KHUDAWADI VOWEL SIGN AU +11301 ; Other_Alphabetic # Mn GRANTHA SIGN CANDRABINDU +11302..11303 ; Other_Alphabetic # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA +1133E..1133F ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I +11340 ; Other_Alphabetic # Mn GRANTHA VOWEL SIGN II +11341..11344 ; Other_Alphabetic # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR +11347..11348 ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI +1134B..1134C ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN OO..GRANTHA VOWEL SIGN AU +11357 ; Other_Alphabetic # Mc GRANTHA AU LENGTH MARK +11362..11363 ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +114B0..114B2 ; Other_Alphabetic # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II +114B3..114B8 ; Other_Alphabetic # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL +114B9 ; Other_Alphabetic # Mc TIRHUTA VOWEL SIGN E +114BA ; Other_Alphabetic # Mn TIRHUTA VOWEL SIGN SHORT E +114BB..114BE ; Other_Alphabetic # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU +114BF..114C0 ; Other_Alphabetic # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA +114C1 ; Other_Alphabetic # Mc TIRHUTA SIGN VISARGA +115AF..115B1 ; Other_Alphabetic # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II +115B2..115B5 ; Other_Alphabetic # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR +115B8..115BB ; Other_Alphabetic # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU +115BC..115BD ; Other_Alphabetic # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA +115BE ; Other_Alphabetic # Mc SIDDHAM SIGN VISARGA +11630..11632 ; Other_Alphabetic # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II +11633..1163A ; Other_Alphabetic # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI +1163B..1163C ; Other_Alphabetic # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU +1163D ; Other_Alphabetic # Mn MODI SIGN ANUSVARA +1163E ; Other_Alphabetic # Mc MODI SIGN VISARGA +11640 ; Other_Alphabetic # Mn MODI SIGN ARDHACANDRA 116AB ; Other_Alphabetic # Mn TAKRI SIGN ANUSVARA 116AC ; Other_Alphabetic # Mc TAKRI SIGN VISARGA 116AD ; Other_Alphabetic # Mn TAKRI VOWEL SIGN AA 116AE..116AF ; Other_Alphabetic # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II 116B0..116B5 ; Other_Alphabetic # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU +16B30..16B36 ; Other_Alphabetic # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F51..16F7E ; Other_Alphabetic # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG +1BC9E ; Other_Alphabetic # Mn DUPLOYAN DOUBLE MARK +1F130..1F149 ; Other_Alphabetic # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z +1F150..1F169 ; Other_Alphabetic # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z +1F170..1F189 ; Other_Alphabetic # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 922 +# Total code points: 1116 # ================================================ @@ -746,6 +814,7 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 1939..193B ; Diacritic # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I 1A75..1A7C ; Diacritic # Mn [8] TAI THAM SIGN TONE-1..TAI THAM SIGN KHUEN-LUE KARAN 1A7F ; Diacritic # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT +1AB0..1ABD ; Diacritic # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW 1B34 ; Diacritic # Mn BALINESE SIGN REREKAN 1B44 ; Diacritic # Mc BALINESE ADEG ADEG 1B6B..1B73 ; Diacritic # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG @@ -760,8 +829,10 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 1CE2..1CE8 ; Diacritic # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL 1CED ; Diacritic # Mn VEDIC SIGN TIRYAK 1CF4 ; Diacritic # Mn VEDIC TONE CANDRA ABOVE +1CF8..1CF9 ; Diacritic # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE 1D2C..1D6A ; Diacritic # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI 1DC4..1DCF ; Diacritic # Mn [12] COMBINING MACRON-ACUTE..COMBINING ZIGZAG BELOW +1DF5 ; Diacritic # Mn COMBINING UP TACK ABOVE 1DFD..1DFF ; Diacritic # Mn [3] COMBINING ALMOST EQUAL TO BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 1FBD ; Diacritic # Sk GREEK KORONIS 1FBF..1FC1 ; Diacritic # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI @@ -779,6 +850,7 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM A66F ; Diacritic # Mn COMBINING CYRILLIC VZMET A67C..A67D ; Diacritic # Mn [2] COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK A67F ; Diacritic # Lm CYRILLIC PAYEROK +A69C..A69D ; Diacritic # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN A6F0..A6F1 ; Diacritic # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS A717..A71F ; Diacritic # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK A720..A721 ; Diacritic # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE @@ -791,26 +863,45 @@ A92E ; Diacritic # Po KAYAH LI SIGN CWI A953 ; Diacritic # Mc REJANG VIRAMA A9B3 ; Diacritic # Mn JAVANESE SIGN CECAK TELU A9C0 ; Diacritic # Mc JAVANESE PANGKON +A9E5 ; Diacritic # Mn MYANMAR SIGN SHAN SAW AA7B ; Diacritic # Mc MYANMAR SIGN PAO KAREN TONE +AA7C ; Diacritic # Mn MYANMAR SIGN TAI LAING TONE-2 +AA7D ; Diacritic # Mc MYANMAR SIGN TAI LAING TONE-5 AABF ; Diacritic # Mn TAI VIET TONE MAI EK AAC0 ; Diacritic # Lo TAI VIET TONE MAI NUENG AAC1 ; Diacritic # Mn TAI VIET TONE MAI THO AAC2 ; Diacritic # Lo TAI VIET TONE MAI SONG AAF6 ; Diacritic # Mn MEETEI MAYEK VIRAMA +AB5B ; Diacritic # Sk MODIFIER BREVE WITH INVERTED BREVE +AB5C..AB5F ; Diacritic # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK ABEC ; Diacritic # Mc MEETEI MAYEK LUM IYEK ABED ; Diacritic # Mn MEETEI MAYEK APUN IYEK FB1E ; Diacritic # Mn HEBREW POINT JUDEO-SPANISH VARIKA -FE20..FE26 ; Diacritic # Mn [7] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON +FE20..FE2D ; Diacritic # Mn [14] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON BELOW FF3E ; Diacritic # Sk FULLWIDTH CIRCUMFLEX ACCENT FF40 ; Diacritic # Sk FULLWIDTH GRAVE ACCENT FF70 ; Diacritic # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK FF9E..FF9F ; Diacritic # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK FFE3 ; Diacritic # Sk FULLWIDTH MACRON +102E0 ; Diacritic # Mn COPTIC EPACT THOUSANDS MARK +10AE5..10AE6 ; Diacritic # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW 110B9..110BA ; Diacritic # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA 11133..11134 ; Diacritic # Mn [2] CHAKMA VIRAMA..CHAKMA MAAYYAA +11173 ; Diacritic # Mn MAHAJANI SIGN NUKTA 111C0 ; Diacritic # Mc SHARADA SIGN VIRAMA +11235 ; Diacritic # Mc KHOJKI SIGN VIRAMA +11236 ; Diacritic # Mn KHOJKI SIGN NUKTA +112E9..112EA ; Diacritic # Mn [2] KHUDAWADI SIGN NUKTA..KHUDAWADI SIGN VIRAMA +1133C ; Diacritic # Mn GRANTHA SIGN NUKTA +1134D ; Diacritic # Mc GRANTHA SIGN VIRAMA +11366..1136C ; Diacritic # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX +11370..11374 ; Diacritic # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +114C2..114C3 ; Diacritic # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA +115BF..115C0 ; Diacritic # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA +1163F ; Diacritic # Mn MODI SIGN VIRAMA 116B6 ; Diacritic # Mc TAKRI SIGN VIRAMA 116B7 ; Diacritic # Mn TAKRI SIGN NUKTA +16AF0..16AF4 ; Diacritic # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16F8F..16F92 ; Diacritic # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16F93..16F9F ; Diacritic # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 1D167..1D169 ; Diacritic # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 @@ -818,8 +909,9 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON 1D17B..1D182 ; Diacritic # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE 1D185..1D18B ; Diacritic # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE 1D1AA..1D1AD ; Diacritic # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO +1E8D0..1E8D6 ; Diacritic # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS -# Total code points: 693 +# Total code points: 766 # ================================================ @@ -841,12 +933,16 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON A015 ; Extender # Lm YI SYLLABLE WU A60C ; Extender # Lm VAI SYLLABLE LENGTHENER A9CF ; Extender # Lm JAVANESE PANGRANGKEP +A9E6 ; Extender # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION AA70 ; Extender # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION AADD ; Extender # Lm TAI VIET SYMBOL SAM AAF3..AAF4 ; Extender # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +1135D ; Extender # Lo GRANTHA SIGN PLUTA +115C6..115C8 ; Extender # Po [3] SIDDHAM REPETITION MARK-1..SIDDHAM REPETITION MARK-3 +16B42..16B43 ; Extender # Lm [2] PAHAWH HMONG SIGN VOS NRUA..PAHAWH HMONG SIGN IB YAM -# Total code points: 31 +# Total code points: 38 # ================================================ @@ -866,17 +962,22 @@ FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND 2170..217F ; Other_Lowercase # Nl [16] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL ONE THOUSAND 24D0..24E9 ; Other_Lowercase # So [26] CIRCLED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z 2C7C..2C7D ; Other_Lowercase # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V +A69C..A69D ; Other_Lowercase # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN A770 ; Other_Lowercase # Lm MODIFIER LETTER US A7F8..A7F9 ; Other_Lowercase # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE +AB5C..AB5F ; Other_Lowercase # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK -# Total code points: 183 +# Total code points: 189 # ================================================ 2160..216F ; Other_Uppercase # Nl [16] ROMAN NUMERAL ONE..ROMAN NUMERAL ONE THOUSAND 24B6..24CF ; Other_Uppercase # So [26] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN CAPITAL LETTER Z +1F130..1F149 ; Other_Uppercase # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z +1F150..1F169 ; Other_Uppercase # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z +1F170..1F189 ; Other_Uppercase # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 42 +# Total code points: 120 # ================================================ @@ -918,10 +1019,15 @@ FFFFE..FFFFF ; Noncharacter_Code_Point # Cn [2] .... +2065 ; Other_Default_Ignorable_Code_Point # Cn 3164 ; Other_Default_Ignorable_Code_Point # Lo HANGUL FILLER FFA0 ; Other_Default_Ignorable_Code_Point # Lo HALFWIDTH HANGUL FILLER FFF0..FFF8 ; Other_Default_Ignorable_Code_Point # Cn [9] .. @@ -975,7 +1081,7 @@ E0002..E001F ; Other_Default_Ignorable_Code_Point # Cn [30] .. E0080..E00FF ; Other_Default_Ignorable_Code_Point # Cn [128] .. E01F0..E0FFF ; Other_Default_Ignorable_Code_Point # Cn [3600] .. -# Total code points: 3780 +# Total code points: 3776 # ================================================ @@ -1060,8 +1166,6 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET 0021 ; STerm # Po EXCLAMATION MARK 002E ; STerm # Po FULL STOP 003F ; STerm # Po QUESTION MARK -055C ; STerm # Po ARMENIAN EXCLAMATION MARK -055E ; STerm # Po ARMENIAN QUESTION MARK 0589 ; STerm # Po ARMENIAN FULL STOP 061F ; STerm # Po ARABIC QUESTION MARK 06D4 ; STerm # Po ARABIC FULL STOP @@ -1084,6 +1188,7 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET 203C..203D ; STerm # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG 2047..2049 ; STerm # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK 2E2E ; STerm # Po REVERSED QUESTION MARK +2E3C ; STerm # Po STENOGRAPHIC FULL STOP 3002 ; STerm # Po IDEOGRAPHIC FULL STOP A4FF ; STerm # Po LISU PUNCTUATION FULL STOP A60E..A60F ; STerm # Po [2] VAI FULL STOP..VAI QUESTION MARK @@ -1107,8 +1212,19 @@ FF61 ; STerm # Po HALFWIDTH IDEOGRAPHIC FULL STOP 110BE..110C1 ; STerm # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA 11141..11143 ; STerm # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK 111C5..111C6 ; STerm # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA +111CD ; STerm # Po SHARADA SUTRA MARK +11238..11239 ; STerm # Po [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA +1123B..1123C ; STerm # Po [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK +115C2..115C3 ; STerm # Po [2] SIDDHAM DANDA..SIDDHAM DOUBLE DANDA +115C9 ; STerm # Po SIDDHAM END OF TEXT MARK +11641..11642 ; STerm # Po [2] MODI DANDA..MODI DOUBLE DANDA +16A6E..16A6F ; STerm # Po [2] MRO DANDA..MRO DOUBLE DANDA +16AF5 ; STerm # Po BASSA VAH FULL STOP +16B37..16B38 ; STerm # Po [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB +16B44 ; STerm # Po PAHAWH HMONG SIGN XAUS +1BC9F ; STerm # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP -# Total code points: 83 +# Total code points: 99 # ================================================ @@ -1210,7 +1326,10 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 21D5..21F3 ; Pattern_Syntax # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW 21F4..22FF ; Pattern_Syntax # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP 2300..2307 ; Pattern_Syntax # So [8] DIAMETER SIGN..WAVY LINE -2308..230B ; Pattern_Syntax # Sm [4] LEFT CEILING..RIGHT FLOOR +2308 ; Pattern_Syntax # Ps LEFT CEILING +2309 ; Pattern_Syntax # Pe RIGHT CEILING +230A ; Pattern_Syntax # Ps LEFT FLOOR +230B ; Pattern_Syntax # Pe RIGHT FLOOR 230C..231F ; Pattern_Syntax # So [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER 2320..2321 ; Pattern_Syntax # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL 2322..2328 ; Pattern_Syntax # So [7] FROWN..KEYBOARD @@ -1222,8 +1341,8 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 239B..23B3 ; Pattern_Syntax # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM 23B4..23DB ; Pattern_Syntax # So [40] TOP SQUARE BRACKET..FUSE 23DC..23E1 ; Pattern_Syntax # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET -23E2..23F3 ; Pattern_Syntax # So [18] WHITE TRAPEZIUM..HOURGLASS WITH FLOWING SAND -23F4..23FF ; Pattern_Syntax # Cn [12] .. +23E2..23FA ; Pattern_Syntax # So [25] WHITE TRAPEZIUM..BLACK CIRCLE FOR RECORD +23FB..23FF ; Pattern_Syntax # Cn [5] .. 2400..2426 ; Pattern_Syntax # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO 2427..243F ; Pattern_Syntax # Cn [25] .. 2440..244A ; Pattern_Syntax # So [11] OCR HOOK..OCR DOUBLE BACKSLASH @@ -1236,9 +1355,7 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 25F8..25FF ; Pattern_Syntax # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE 2600..266E ; Pattern_Syntax # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN 266F ; Pattern_Syntax # Sm MUSIC SHARP SIGN -2670..26FF ; Pattern_Syntax # So [144] WEST SYRIAC CROSS..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE -2700 ; Pattern_Syntax # Cn -2701..2767 ; Pattern_Syntax # So [103] UPPER BLADE SCISSORS..ROTATED FLORAL HEART BULLET +2670..2767 ; Pattern_Syntax # So [248] WEST SYRIAC CROSS..ROTATED FLORAL HEART BULLET 2768 ; Pattern_Syntax # Ps MEDIUM LEFT PARENTHESIS ORNAMENT 2769 ; Pattern_Syntax # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT 276A ; Pattern_Syntax # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT @@ -1306,9 +1423,16 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 2B30..2B44 ; Pattern_Syntax # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET 2B45..2B46 ; Pattern_Syntax # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW 2B47..2B4C ; Pattern_Syntax # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR -2B4D..2B4F ; Pattern_Syntax # Cn [3] .. -2B50..2B59 ; Pattern_Syntax # So [10] WHITE MEDIUM STAR..HEAVY CIRCLED SALTIRE -2B5A..2BFF ; Pattern_Syntax # Cn [166] .. +2B4D..2B73 ; Pattern_Syntax # So [39] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR +2B74..2B75 ; Pattern_Syntax # Cn [2] .. +2B76..2B95 ; Pattern_Syntax # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW +2B96..2B97 ; Pattern_Syntax # Cn [2] .. +2B98..2BB9 ; Pattern_Syntax # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX +2BBA..2BBC ; Pattern_Syntax # Cn [3] .. +2BBD..2BC8 ; Pattern_Syntax # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED +2BC9 ; Pattern_Syntax # Cn +2BCA..2BD1 ; Pattern_Syntax # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN +2BD2..2BFF ; Pattern_Syntax # Cn [46] .. 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 @@ -1342,7 +1466,11 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 2E2F ; Pattern_Syntax # Lm VERTICAL TILDE 2E30..2E39 ; Pattern_Syntax # Po [10] RING POINT..TOP HALF SECTION SIGN 2E3A..2E3B ; Pattern_Syntax # Pd [2] TWO-EM DASH..THREE-EM DASH -2E3C..2E7F ; Pattern_Syntax # Cn [68] .. +2E3C..2E3F ; Pattern_Syntax # Po [4] STENOGRAPHIC FULL STOP..CAPITULUM +2E40 ; Pattern_Syntax # Pd DOUBLE HYPHEN +2E41 ; Pattern_Syntax # Po REVERSED COMMA +2E42 ; Pattern_Syntax # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43..2E7F ; Pattern_Syntax # Cn [61] .. 3001..3003 ; Pattern_Syntax # Po [3] IDEOGRAPHIC COMMA..DITTO MARK 3008 ; Pattern_Syntax # Ps LEFT ANGLE BRACKET 3009 ; Pattern_Syntax # Pe RIGHT ANGLE BRACKET @@ -1368,8 +1496,8 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 301E..301F ; Pattern_Syntax # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK 3020 ; Pattern_Syntax # So POSTAL MARK FACE 3030 ; Pattern_Syntax # Pd WAVY DASH -FD3E ; Pattern_Syntax # Ps ORNATE LEFT PARENTHESIS -FD3F ; Pattern_Syntax # Pe ORNATE RIGHT PARENTHESIS +FD3E ; Pattern_Syntax # Pe ORNATE LEFT PARENTHESIS +FD3F ; Pattern_Syntax # Ps ORNATE RIGHT PARENTHESIS FE45..FE46 ; Pattern_Syntax # Po [2] SESAME DOT..WHITE SESAME DOT # Total code points: 2760 diff --git a/jdk/make/data/unicodedata/Scripts.txt b/jdk/make/data/unicodedata/Scripts.txt index 1a8e7229cc6..0b69438a571 100644 --- a/jdk/make/data/unicodedata/Scripts.txt +++ b/jdk/make/data/unicodedata/Scripts.txt @@ -1,8 +1,8 @@ -# Scripts-6.2.0.txt -# Date: 2012-06-04, 17:21:29 GMT [MD] +# Scripts-7.0.0.txt +# Date: 2014-05-15, 00:11:35 GMT [MD] # # Unicode Character Database -# Copyright (c) 1991-2012 Unicode, Inc. +# Copyright (c) 1991-2014 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # For documentation, see http://www.unicode.org/reports/tr44/ @@ -83,8 +83,10 @@ 0385 ; Common # Sk GREEK DIALYTIKA TONOS 0387 ; Common # Po GREEK ANO TELEIA 0589 ; Common # Po ARMENIAN FULL STOP +0605 ; Common # Cf ARABIC NUMBER MARK ABOVE 060C ; Common # Po ARABIC COMMA 061B ; Common # Po ARABIC SEMICOLON +061C ; Common # Cf ARABIC LETTER MARK 061F ; Common # Po ARABIC QUESTION MARK 0640 ; Common # Lm ARABIC TATWEEL 0660..0669 ; Common # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE @@ -136,7 +138,7 @@ 2055..205E ; Common # Po [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS 205F ; Common # Zs MEDIUM MATHEMATICAL SPACE 2060..2064 ; Common # Cf [5] WORD JOINER..INVISIBLE PLUS -206A..206F ; Common # Cf [6] INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES +2066..206F ; Common # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES 2070 ; Common # No SUPERSCRIPT ZERO 2074..2079 ; Common # No [6] SUPERSCRIPT FOUR..SUPERSCRIPT NINE 207A..207C ; Common # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN @@ -146,7 +148,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..20BA ; Common # Sc [27] EURO-CURRENCY SIGN..TURKISH LIRA SIGN +20A0..20BD ; Common # Sc [30] EURO-CURRENCY SIGN..RUBLE 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 @@ -200,7 +202,10 @@ 21D5..21F3 ; Common # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW 21F4..22FF ; Common # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP 2300..2307 ; Common # So [8] DIAMETER SIGN..WAVY LINE -2308..230B ; Common # Sm [4] LEFT CEILING..RIGHT FLOOR +2308 ; Common # Ps LEFT CEILING +2309 ; Common # Pe RIGHT CEILING +230A ; Common # Ps LEFT FLOOR +230B ; Common # Pe RIGHT FLOOR 230C..231F ; Common # So [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER 2320..2321 ; Common # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL 2322..2328 ; Common # So [7] FROWN..KEYBOARD @@ -212,7 +217,7 @@ 239B..23B3 ; Common # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM 23B4..23DB ; Common # So [40] TOP SQUARE BRACKET..FUSE 23DC..23E1 ; Common # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET -23E2..23F3 ; Common # So [18] WHITE TRAPEZIUM..HOURGLASS WITH FLOWING SAND +23E2..23FA ; Common # So [25] WHITE TRAPEZIUM..BLACK CIRCLE FOR RECORD 2400..2426 ; Common # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO 2440..244A ; Common # So [11] OCR HOOK..OCR DOUBLE BACKSLASH 2460..249B ; Common # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP @@ -226,8 +231,7 @@ 25F8..25FF ; Common # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE 2600..266E ; Common # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN 266F ; Common # Sm MUSIC SHARP SIGN -2670..26FF ; Common # So [144] WEST SYRIAC CROSS..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE -2701..2767 ; Common # So [103] UPPER BLADE SCISSORS..ROTATED FLORAL HEART BULLET +2670..2767 ; Common # So [248] WEST SYRIAC CROSS..ROTATED FLORAL HEART BULLET 2768 ; Common # Ps MEDIUM LEFT PARENTHESIS ORNAMENT 2769 ; Common # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT 276A ; Common # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT @@ -295,7 +299,11 @@ 2B30..2B44 ; Common # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET 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 -2B50..2B59 ; Common # So [10] WHITE MEDIUM STAR..HEAVY CIRCLED SALTIRE +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 +2B98..2BB9 ; Common # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX +2BBD..2BC8 ; Common # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED +2BCA..2BD1 ; Common # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN 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 @@ -329,6 +337,10 @@ 2E2F ; Common # Lm VERTICAL TILDE 2E30..2E39 ; Common # Po [10] RING POINT..TOP HALF SECTION SIGN 2E3A..2E3B ; Common # Pd [2] TWO-EM DASH..THREE-EM DASH +2E3C..2E3F ; Common # Po [4] STENOGRAPHIC FULL STOP..CAPITULUM +2E40 ; Common # Pd DOUBLE HYPHEN +2E41 ; Common # Po REVERSED COMMA +2E42 ; Common # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK 2FF0..2FFB ; Common # So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID 3000 ; Common # Zs IDEOGRAPHIC SPACE 3001..3003 ; Common # Po [3] IDEOGRAPHIC COMMA..DITTO MARK @@ -392,9 +404,11 @@ A830..A835 ; Common # No [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC A836..A837 ; Common # So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK A838 ; Common # Sc NORTH INDIC RUPEE MARK A839 ; Common # So NORTH INDIC QUANTITY MARK -FD3E ; Common # Ps ORNATE LEFT PARENTHESIS -FD3F ; Common # Pe ORNATE RIGHT PARENTHESIS -FDFD ; Common # So ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM +A92E ; Common # Po KAYAH LI SIGN CWI +A9CF ; Common # Lm JAVANESE PANGRANGKEP +AB5B ; Common # Sk MODIFIER BREVE WITH INVERTED BREVE +FD3E ; Common # Pe ORNATE LEFT PARENTHESIS +FD3F ; Common # Ps ORNATE RIGHT PARENTHESIS FE10..FE16 ; Common # Po [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK FE17 ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET FE18 ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET @@ -487,6 +501,8 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 10137..1013F ; Common # So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT 10190..1019B ; Common # So [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN 101D0..101FC ; Common # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND +102E1..102FB ; Common # No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED +1BCA0..1BCA3 ; Common # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP 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 1D129..1D164 ; Common # So [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE @@ -543,10 +559,10 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1F000..1F02B ; Common # So [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK 1F030..1F093 ; Common # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06 1F0A0..1F0AE ; Common # So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES -1F0B1..1F0BE ; Common # So [14] PLAYING CARD ACE OF HEARTS..PLAYING CARD KING OF HEARTS +1F0B1..1F0BF ; Common # So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER 1F0C1..1F0CF ; Common # So [15] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER -1F0D1..1F0DF ; Common # So [15] PLAYING CARD ACE OF CLUBS..PLAYING CARD WHITE JOKER -1F100..1F10A ; Common # No [11] DIGIT ZERO FULL STOP..DIGIT NINE COMMA +1F0D1..1F0F5 ; Common # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21 +1F100..1F10C ; Common # No [13] DIGIT ZERO FULL STOP..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO 1F110..1F12E ; Common # So [31] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED WZ 1F130..1F16B ; Common # So [60] SQUARED LATIN CAPITAL LETTER A..RAISED MD SIGN 1F170..1F19A ; Common # So [43] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VS @@ -555,28 +571,29 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1F210..1F23A ; Common # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6 1F240..1F248 ; Common # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 1F250..1F251 ; Common # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT -1F300..1F320 ; Common # So [33] CYCLONE..SHOOTING STAR -1F330..1F335 ; Common # So [6] CHESTNUT..CACTUS -1F337..1F37C ; Common # So [70] TULIP..BABY BOTTLE -1F380..1F393 ; Common # So [20] RIBBON..GRADUATION CAP -1F3A0..1F3C4 ; Common # So [37] CAROUSEL HORSE..SURFER -1F3C6..1F3CA ; Common # So [5] TROPHY..SWIMMER -1F3E0..1F3F0 ; Common # So [17] HOUSE BUILDING..EUROPEAN CASTLE -1F400..1F43E ; Common # So [63] RAT..PAW PRINTS -1F440 ; Common # So EYES -1F442..1F4F7 ; Common # So [182] EAR..CAMERA -1F4F9..1F4FC ; Common # So [4] VIDEO CAMERA..VIDEOCASSETTE -1F500..1F53D ; Common # So [62] TWISTED RIGHTWARDS ARROWS..DOWN-POINTING SMALL RED TRIANGLE -1F540..1F543 ; Common # So [4] CIRCLED CROSS POMMEE..NOTCHED LEFT SEMICIRCLE WITH THREE DOTS -1F550..1F567 ; Common # So [24] CLOCK FACE ONE OCLOCK..CLOCK FACE TWELVE-THIRTY -1F5FB..1F640 ; Common # So [70] MOUNT FUJI..WEARY CAT FACE -1F645..1F64F ; Common # So [11] FACE WITH NO GOOD GESTURE..PERSON WITH FOLDED HANDS -1F680..1F6C5 ; Common # So [70] ROCKET..LEFT LUGGAGE +1F300..1F32C ; Common # So [45] CYCLONE..WIND BLOWING FACE +1F330..1F37D ; Common # So [78] CHESTNUT..FORK AND KNIFE WITH PLATE +1F380..1F3CE ; Common # So [79] RIBBON..RACING CAR +1F3D4..1F3F7 ; Common # So [36] SNOW CAPPED MOUNTAIN..LABEL +1F400..1F4FE ; Common # So [255] RAT..PORTABLE STEREO +1F500..1F54A ; Common # So [75] TWISTED RIGHTWARDS ARROWS..DOVE OF PEACE +1F550..1F579 ; Common # So [42] CLOCK FACE ONE OCLOCK..JOYSTICK +1F57B..1F5A3 ; Common # So [41] LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX +1F5A5..1F642 ; Common # So [158] DESKTOP COMPUTER..SLIGHTLY SMILING FACE +1F645..1F6CF ; Common # So [139] FACE WITH NO GOOD GESTURE..BED +1F6E0..1F6EC ; Common # So [13] HAMMER AND WRENCH..AIRPLANE ARRIVING +1F6F0..1F6F3 ; Common # So [4] SATELLITE..PASSENGER SHIP 1F700..1F773 ; Common # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE +1F780..1F7D4 ; Common # So [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR +1F800..1F80B ; Common # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD +1F810..1F847 ; Common # So [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW +1F850..1F859 ; Common # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW +1F860..1F887 ; Common # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW +1F890..1F8AD ; Common # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS E0001 ; Common # Cf LANGUAGE TAG E0020..E007F ; Common # Cf [96] TAG SPACE..CANCEL TAG -# Total code points: 6413 +# Total code points: 7129 # ================================================ @@ -618,16 +635,20 @@ A722..A76F ; Latin # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN 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 -A790..A793 ; Latin # L& [4] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER C WITH BAR -A7A0..A7AA ; Latin # L& [11] LATIN CAPITAL LETTER G WITH OBLIQUE STROKE..LATIN CAPITAL LETTER H WITH HOOK +A790..A7AD ; Latin # L& [30] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER L WITH BELT +A7B0..A7B1 ; Latin # L& [2] LATIN CAPITAL LETTER TURNED K..LATIN CAPITAL LETTER TURNED T +A7F7 ; Latin # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; Latin # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE A7FA ; Latin # L& LATIN LETTER SMALL CAPITAL TURNED M A7FB..A7FF ; Latin # Lo [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M +AB30..AB5A ; Latin # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG +AB5C..AB5F ; Latin # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK +AB64 ; Latin # L& LATIN SMALL LETTER INVERTED ALPHA FB00..FB06 ; Latin # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST FF21..FF3A ; Latin # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z -# Total code points: 1272 +# Total code points: 1338 # ================================================ @@ -636,6 +657,7 @@ FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 0376..0377 ; Greek # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA 037A ; Greek # Lm GREEK YPOGEGRAMMENI 037B..037D ; Greek # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL +037F ; Greek # L& GREEK CAPITAL LETTER YOT 0384 ; Greek # Sk GREEK TONOS 0386 ; Greek # L& GREEK CAPITAL LETTER ALPHA WITH TONOS 0388..038A ; Greek # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS @@ -675,15 +697,18 @@ FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 1FF6..1FFC ; Greek # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI 1FFD..1FFE ; Greek # Sk [2] GREEK OXIA..GREEK DASIA 2126 ; Greek # L& OHM SIGN +AB65 ; Greek # L& GREEK LETTER SMALL CAPITAL OMEGA 10140..10174 ; Greek # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS 10175..10178 ; Greek # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN 10179..10189 ; Greek # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN -1018A ; Greek # No GREEK ZERO SIGN +1018A..1018B ; Greek # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN +1018C ; Greek # So GREEK SINUSOID SIGN +101A0 ; Greek # So GREEK SYMBOL TAU RHO 1D200..1D241 ; Greek # So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54 1D242..1D244 ; Greek # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME 1D245 ; Greek # So GREEK MUSICAL LEIMMA -# Total code points: 511 +# Total code points: 516 # ================================================ @@ -692,7 +717,7 @@ FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 0483..0484 ; Cyrillic # Mn [2] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC PALATALIZATION 0487 ; Cyrillic # Mn COMBINING CYRILLIC POKRYTIE 0488..0489 ; Cyrillic # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN -048A..0527 ; Cyrillic # L& [158] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER SHHA WITH DESCENDER +048A..052F ; Cyrillic # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER 1D2B ; Cyrillic # L& CYRILLIC LETTER SMALL CAPITAL EL 1D78 ; Cyrillic # Lm MODIFIER LETTER CYRILLIC EN 2DE0..2DFF ; Cyrillic # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS @@ -704,10 +729,11 @@ A673 ; Cyrillic # Po SLAVONIC ASTERISK A674..A67D ; Cyrillic # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK A67E ; Cyrillic # Po CYRILLIC KAVYKA A67F ; Cyrillic # Lm CYRILLIC PAYEROK -A680..A697 ; Cyrillic # L& [24] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER SHWE +A680..A69B ; Cyrillic # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O +A69C..A69D ; Cyrillic # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN A69F ; Cyrillic # Mn COMBINING CYRILLIC LETTER IOTIFIED E -# Total code points: 417 +# Total code points: 431 # ================================================ @@ -716,10 +742,11 @@ A69F ; Cyrillic # Mn COMBINING CYRILLIC LETTER IOTIFIED E 055A..055F ; Armenian # Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK 0561..0587 ; Armenian # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN 058A ; Armenian # Pd ARMENIAN HYPHEN +058D..058E ; Armenian # So [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN 058F ; Armenian # Sc ARMENIAN DRAM SIGN FB13..FB17 ; Armenian # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH -# Total code points: 91 +# Total code points: 93 # ================================================ @@ -779,9 +806,8 @@ FB46..FB4F ; Hebrew # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATU 06FD..06FE ; Arabic # So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN 06FF ; Arabic # Lo ARABIC LETTER HEH WITH INVERTED V 0750..077F ; Arabic # Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE -08A0 ; Arabic # Lo ARABIC LETTER BEH WITH SMALL V BELOW -08A2..08AC ; Arabic # Lo [11] ARABIC LETTER JEEM WITH TWO DOTS ABOVE..ARABIC LETTER ROHINGYA YEH -08E4..08FE ; Arabic # Mn [27] ARABIC CURLY FATHA..ARABIC DAMMA WITH DOT +08A0..08B2 ; Arabic # Lo [19] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER ZAIN WITH INVERTED V ABOVE +08E4..08FF ; Arabic # Mn [28] ARABIC CURLY FATHA..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..FBC1 ; Arabic # Sk [16] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL SMALL TAH BELOW FBD3..FD3D ; Arabic # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM @@ -789,6 +815,7 @@ FD50..FD8F ; Arabic # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIA FD92..FDC7 ; Arabic # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM FDF0..FDFB ; Arabic # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU FDFC ; Arabic # Sc RIAL SIGN +FDFD ; Arabic # So ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM FE70..FE74 ; Arabic # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM 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 @@ -827,7 +854,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: 1235 +# Total code points: 1244 # ================================================ @@ -870,17 +897,17 @@ FE76..FEFC ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LA 0966..096F ; Devanagari # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE 0970 ; Devanagari # Po DEVANAGARI ABBREVIATION SIGN 0971 ; Devanagari # Lm DEVANAGARI SIGN HIGH SPACING DOT -0972..0977 ; Devanagari # Lo [6] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER UUE -0979..097F ; Devanagari # Lo [7] DEVANAGARI LETTER ZHA..DEVANAGARI LETTER BBA +0972..097F ; Devanagari # Lo [14] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER BBA A8E0..A8F1 ; Devanagari # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA A8F2..A8F7 ; Devanagari # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA A8F8..A8FA ; Devanagari # Po [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE -# Total code points: 151 +# Total code points: 152 # ================================================ +0980 ; Bengali # Lo BENGALI ANJI 0981 ; Bengali # Mn BENGALI SIGN CANDRABINDU 0982..0983 ; Bengali # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA 0985..098C ; Bengali # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L @@ -908,7 +935,7 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 09FA ; Bengali # So BENGALI ISSHAR 09FB ; Bengali # Sc BENGALI GANDA MARK -# Total code points: 92 +# Total code points: 93 # ================================================ @@ -1025,12 +1052,12 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE # ================================================ +0C00 ; Telugu # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE 0C01..0C03 ; Telugu # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA 0C05..0C0C ; Telugu # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L 0C0E..0C10 ; Telugu # Lo [3] TELUGU LETTER E..TELUGU LETTER AI 0C12..0C28 ; Telugu # Lo [23] TELUGU LETTER O..TELUGU LETTER NA -0C2A..0C33 ; Telugu # Lo [10] TELUGU LETTER PA..TELUGU LETTER LLA -0C35..0C39 ; Telugu # Lo [5] TELUGU LETTER VA..TELUGU LETTER HA +0C2A..0C39 ; Telugu # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA 0C3D ; Telugu # Lo TELUGU SIGN AVAGRAHA 0C3E..0C40 ; Telugu # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II 0C41..0C44 ; Telugu # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR @@ -1044,10 +1071,11 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 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: 93 +# Total code points: 95 # ================================================ +0C81 ; Kannada # Mn KANNADA SIGN CANDRABINDU 0C82..0C83 ; Kannada # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 0C85..0C8C ; Kannada # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L 0C8E..0C90 ; Kannada # Lo [3] KANNADA LETTER E..KANNADA LETTER AI @@ -1070,10 +1098,11 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 0CE6..0CEF ; Kannada # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE 0CF1..0CF2 ; Kannada # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA -# Total code points: 86 +# Total code points: 87 # ================================================ +0D01 ; Malayalam # Mn MALAYALAM SIGN CANDRABINDU 0D02..0D03 ; Malayalam # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D05..0D0C ; Malayalam # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L 0D0E..0D10 ; Malayalam # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI @@ -1093,7 +1122,7 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 0D79 ; Malayalam # So MALAYALAM DATE MARK 0D7A..0D7F ; Malayalam # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K -# Total code points: 98 +# Total code points: 99 # ================================================ @@ -1108,10 +1137,12 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 0DD2..0DD4 ; Sinhala # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA 0DD6 ; Sinhala # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA 0DD8..0DDF ; Sinhala # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA +0DE6..0DEF ; Sinhala # Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE 0DF2..0DF3 ; Sinhala # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA 0DF4 ; Sinhala # Po SINHALA PUNCTUATION KUNDDALIYA +111E1..111F4 ; Sinhala # No [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND -# Total code points: 80 +# Total code points: 110 # ================================================ @@ -1234,14 +1265,23 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 109A..109C ; Myanmar # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A 109D ; Myanmar # Mn MYANMAR VOWEL SIGN AITON AI 109E..109F ; Myanmar # So [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION +A9E0..A9E4 ; Myanmar # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA +A9E5 ; Myanmar # Mn MYANMAR SIGN SHAN SAW +A9E6 ; Myanmar # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION +A9E7..A9EF ; Myanmar # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA +A9F0..A9F9 ; Myanmar # Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE +A9FA..A9FE ; Myanmar # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA AA60..AA6F ; Myanmar # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA AA70 ; Myanmar # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION AA71..AA76 ; Myanmar # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM AA77..AA79 ; Myanmar # So [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO AA7A ; Myanmar # Lo MYANMAR LETTER AITON RA AA7B ; Myanmar # Mc MYANMAR SIGN PAO KAREN TONE +AA7C ; Myanmar # Mn MYANMAR SIGN TAI LAING TONE-2 +AA7D ; Myanmar # Mc MYANMAR SIGN TAI LAING TONE-5 +AA7E..AA7F ; Myanmar # Lo [2] MYANMAR LETTER SHWE PALAUNG CHA..MYANMAR LETTER SHWE PALAUNG SHA -# Total code points: 188 +# Total code points: 223 # ================================================ @@ -1345,8 +1385,9 @@ AB28..AB2E ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO 16A0..16EA ; Runic # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X 16EE..16F0 ; Runic # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL +16F1..16F8 ; Runic # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC -# Total code points: 78 +# Total code points: 86 # ================================================ @@ -1377,7 +1418,7 @@ AB28..AB2E ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO 1806 ; Mongolian # Pd MONGOLIAN TODO SOFT HYPHEN 1807..180A ; Mongolian # Po [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU 180B..180D ; Mongolian # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE -180E ; Mongolian # Zs MONGOLIAN VOWEL SEPARATOR +180E ; Mongolian # Cf MONGOLIAN VOWEL SEPARATOR 1810..1819 ; Mongolian # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE 1820..1842 ; Mongolian # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI 1843 ; Mongolian # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN @@ -1452,10 +1493,10 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE # ================================================ -10300..1031E ; Old_Italic # Lo [31] OLD ITALIC LETTER A..OLD ITALIC LETTER UU +10300..1031F ; Old_Italic # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS 10320..10323 ; Old_Italic # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY -# Total code points: 35 +# Total code points: 36 # ================================================ @@ -1479,12 +1520,15 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE 064B..0655 ; Inherited # Mn [11] ARABIC FATHATAN..ARABIC HAMZA BELOW 0670 ; Inherited # Mn ARABIC LETTER SUPERSCRIPT ALEF 0951..0952 ; Inherited # Mn [2] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI STRESS SIGN ANUDATTA +1AB0..1ABD ; Inherited # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW +1ABE ; Inherited # Me COMBINING PARENTHESES OVERLAY 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 1CED ; Inherited # Mn VEDIC SIGN TIRYAK 1CF4 ; Inherited # Mn VEDIC TONE CANDRA ABOVE -1DC0..1DE6 ; Inherited # Mn [39] COMBINING DOTTED GRAVE ACCENT..COMBINING LATIN SMALL LETTER Z +1CF8..1CF9 ; Inherited # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE +1DC0..1DF5 ; Inherited # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE 1DFC..1DFF ; Inherited # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 200C..200D ; Inherited # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER 20D0..20DC ; Inherited # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE @@ -1495,15 +1539,16 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE 302A..302D ; Inherited # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK 3099..309A ; Inherited # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK FE00..FE0F ; Inherited # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 -FE20..FE26 ; Inherited # Mn [7] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON +FE20..FE2D ; Inherited # Mn [14] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON BELOW 101FD ; Inherited # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE +102E0 ; Inherited # Mn COPTIC EPACT THOUSANDS MARK 1D167..1D169 ; Inherited # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 1D17B..1D182 ; Inherited # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE 1D185..1D18B ; Inherited # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE 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: 523 +# Total code points: 563 # ================================================ @@ -1537,7 +1582,7 @@ E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-2 # ================================================ -1900..191C ; Limbu # Lo [29] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER HA +1900..191E ; Limbu # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA 1920..1922 ; Limbu # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U 1923..1926 ; Limbu # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU 1927..1928 ; Limbu # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O @@ -1550,7 +1595,7 @@ E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-2 1944..1945 ; Limbu # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK 1946..194F ; Limbu # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE -# Total code points: 66 +# Total code points: 68 # ================================================ @@ -1612,7 +1657,8 @@ E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-2 1A00..1A16 ; Buginese # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA 1A17..1A18 ; Buginese # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U -1A19..1A1B ; Buginese # Mc [3] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN AE +1A19..1A1A ; Buginese # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O +1A1B ; Buginese # Mn BUGINESE VOWEL SIGN AE 1A1E..1A1F ; Buginese # Po [2] BUGINESE PALLAWA..BUGINESE END OF SECTION # Total code points: 30 @@ -1724,11 +1770,11 @@ A828..A82B ; Syloti_Nagri # So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI # ================================================ -12000..1236E ; Cuneiform # Lo [879] CUNEIFORM SIGN A..CUNEIFORM SIGN ZUM -12400..12462 ; Cuneiform # Nl [99] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER -12470..12473 ; Cuneiform # Po [4] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON +12000..12398 ; Cuneiform # Lo [921] CUNEIFORM SIGN A..CUNEIFORM SIGN UM TIMES ME +12400..1246E ; Cuneiform # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM +12470..12474 ; Cuneiform # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON -# Total code points: 982 +# Total code points: 1037 # ================================================ @@ -1767,8 +1813,7 @@ A874..A877 ; Phags_Pa # Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOU 1BA6..1BA7 ; Sundanese # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG 1BA8..1BA9 ; Sundanese # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG 1BAA ; Sundanese # Mc SUNDANESE SIGN PAMAAEH -1BAB ; Sundanese # Mn SUNDANESE SIGN VIRAMA -1BAC..1BAD ; Sundanese # Mc [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA +1BAB..1BAD ; Sundanese # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA 1BAE..1BAF ; Sundanese # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA 1BB0..1BB9 ; Sundanese # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE 1BBA..1BBF ; Sundanese # Lo [6] SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M @@ -1825,9 +1870,9 @@ A8D0..A8D9 ; Saurashtra # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NI A900..A909 ; Kayah_Li # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE A90A..A925 ; Kayah_Li # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO A926..A92D ; Kayah_Li # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU -A92E..A92F ; Kayah_Li # Po [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA +A92F ; Kayah_Li # Po KAYAH LI SIGN SHYA -# Total code points: 48 +# Total code points: 47 # ================================================ @@ -1974,11 +2019,10 @@ A9BA..A9BB ; Javanese # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL S A9BC ; Javanese # Mn JAVANESE VOWEL SIGN PEPET A9BD..A9C0 ; Javanese # Mc [4] JAVANESE CONSONANT SIGN KERET..JAVANESE PANGKON A9C1..A9CD ; Javanese # Po [13] JAVANESE LEFT RERENGGAN..JAVANESE TURNED PADA PISELEH -A9CF ; Javanese # Lm JAVANESE PANGRANGKEP A9D0..A9D9 ; Javanese # Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE A9DE..A9DF ; Javanese # Po [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN -# Total code points: 91 +# Total code points: 90 # ================================================ @@ -2080,8 +2124,9 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI 11047..1104D ; Brahmi # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS 11052..11065 ; Brahmi # No [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND 11066..1106F ; Brahmi # Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE +1107F ; Brahmi # Mn BRAHMI NUMBER JOINER -# Total code points: 108 +# Total code points: 109 # ================================================ @@ -2136,9 +2181,11 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI 111BF..111C0 ; Sharada # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA 111C1..111C4 ; Sharada # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM 111C5..111C8 ; Sharada # Po [4] SHARADA DANDA..SHARADA SEPARATOR +111CD ; Sharada # Po SHARADA SUTRA MARK 111D0..111D9 ; Sharada # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE +111DA ; Sharada # Lo SHARADA EKAM -# Total code points: 83 +# Total code points: 85 # ================================================ @@ -2161,4 +2208,244 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI # Total code points: 66 +# ================================================ + +10530..10563 ; Caucasian_Albanian # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW +1056F ; Caucasian_Albanian # Po CAUCASIAN ALBANIAN CITATION MARK + +# Total code points: 53 + +# ================================================ + +16AD0..16AED ; Bassa_Vah # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I +16AF0..16AF4 ; Bassa_Vah # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE +16AF5 ; Bassa_Vah # Po BASSA VAH FULL STOP + +# Total code points: 36 + +# ================================================ + +1BC00..1BC6A ; Duployan # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M +1BC70..1BC7C ; Duployan # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK +1BC80..1BC88 ; Duployan # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL +1BC90..1BC99 ; Duployan # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW +1BC9C ; Duployan # So DUPLOYAN SIGN O WITH CROSS +1BC9D..1BC9E ; Duployan # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1BC9F ; Duployan # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP + +# Total code points: 143 + +# ================================================ + +10500..10527 ; Elbasan # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE + +# Total code points: 40 + +# ================================================ + +11301 ; Grantha # Mn GRANTHA SIGN CANDRABINDU +11302..11303 ; Grantha # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA +11305..1130C ; Grantha # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L +1130F..11310 ; Grantha # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI +11313..11328 ; Grantha # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA +1132A..11330 ; Grantha # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA +11332..11333 ; Grantha # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA +11335..11339 ; Grantha # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA +1133C ; Grantha # Mn GRANTHA SIGN NUKTA +1133D ; Grantha # Lo GRANTHA SIGN AVAGRAHA +1133E..1133F ; Grantha # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I +11340 ; Grantha # Mn GRANTHA VOWEL SIGN II +11341..11344 ; Grantha # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR +11347..11348 ; Grantha # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI +1134B..1134D ; Grantha # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA +11357 ; Grantha # Mc GRANTHA AU LENGTH MARK +1135D..11361 ; Grantha # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11362..11363 ; Grantha # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +11366..1136C ; Grantha # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX +11370..11374 ; Grantha # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA + +# Total code points: 83 + +# ================================================ + +16B00..16B2F ; Pahawh_Hmong # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU +16B30..16B36 ; Pahawh_Hmong # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM +16B37..16B3B ; Pahawh_Hmong # Po [5] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS FEEM +16B3C..16B3F ; Pahawh_Hmong # So [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB +16B40..16B43 ; Pahawh_Hmong # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM +16B44 ; Pahawh_Hmong # Po PAHAWH HMONG SIGN XAUS +16B45 ; Pahawh_Hmong # So PAHAWH HMONG SIGN CIM TSOV ROG +16B50..16B59 ; Pahawh_Hmong # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE +16B5B..16B61 ; Pahawh_Hmong # No [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS +16B63..16B77 ; Pahawh_Hmong # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS +16B7D..16B8F ; Pahawh_Hmong # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ + +# Total code points: 127 + +# ================================================ + +11200..11211 ; Khojki # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA +11213..1122B ; Khojki # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA +1122C..1122E ; Khojki # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II +1122F..11231 ; Khojki # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI +11232..11233 ; Khojki # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU +11234 ; Khojki # Mn KHOJKI SIGN ANUSVARA +11235 ; Khojki # Mc KHOJKI SIGN VIRAMA +11236..11237 ; Khojki # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA +11238..1123D ; Khojki # Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN + +# Total code points: 61 + +# ================================================ + +10600..10736 ; Linear_A # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 +10740..10755 ; Linear_A # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE +10760..10767 ; Linear_A # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 + +# Total code points: 341 + +# ================================================ + +11150..11172 ; Mahajani # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA +11173 ; Mahajani # Mn MAHAJANI SIGN NUKTA +11174..11175 ; Mahajani # Po [2] MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK +11176 ; Mahajani # Lo MAHAJANI LIGATURE SHRI + +# Total code points: 39 + +# ================================================ + +10AC0..10AC7 ; Manichaean # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW +10AC8 ; Manichaean # So MANICHAEAN SIGN UD +10AC9..10AE4 ; Manichaean # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW +10AE5..10AE6 ; Manichaean # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW +10AEB..10AEF ; Manichaean # No [5] MANICHAEAN NUMBER ONE..MANICHAEAN NUMBER ONE HUNDRED +10AF0..10AF6 ; Manichaean # Po [7] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION LINE FILLER + +# Total code points: 51 + +# ================================================ + +1E800..1E8C4 ; Mende_Kikakui # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON +1E8C7..1E8CF ; Mende_Kikakui # No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE +1E8D0..1E8D6 ; Mende_Kikakui # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS + +# Total code points: 213 + +# ================================================ + +11600..1162F ; Modi # Lo [48] MODI LETTER A..MODI LETTER LLA +11630..11632 ; Modi # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II +11633..1163A ; Modi # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI +1163B..1163C ; Modi # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU +1163D ; Modi # Mn MODI SIGN ANUSVARA +1163E ; Modi # Mc MODI SIGN VISARGA +1163F..11640 ; Modi # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA +11641..11643 ; Modi # Po [3] MODI DANDA..MODI ABBREVIATION SIGN +11644 ; Modi # Lo MODI SIGN HUVA +11650..11659 ; Modi # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE + +# Total code points: 79 + +# ================================================ + +16A40..16A5E ; Mro # Lo [31] MRO LETTER TA..MRO LETTER TEK +16A60..16A69 ; Mro # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE +16A6E..16A6F ; Mro # Po [2] MRO DANDA..MRO DOUBLE DANDA + +# Total code points: 43 + +# ================================================ + +10A80..10A9C ; Old_North_Arabian # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH +10A9D..10A9F ; Old_North_Arabian # No [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY + +# Total code points: 32 + +# ================================================ + +10880..1089E ; Nabataean # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW +108A7..108AF ; Nabataean # No [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED + +# Total code points: 40 + +# ================================================ + +10860..10876 ; Palmyrene # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW +10877..10878 ; Palmyrene # So [2] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE RIGHT-POINTING FLEURON +10879..1087F ; Palmyrene # No [7] PALMYRENE NUMBER ONE..PALMYRENE NUMBER TWENTY + +# Total code points: 32 + +# ================================================ + +11AC0..11AF8 ; Pau_Cin_Hau # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL + +# Total code points: 57 + +# ================================================ + +10350..10375 ; Old_Permic # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA +10376..1037A ; Old_Permic # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII + +# Total code points: 43 + +# ================================================ + +10B80..10B91 ; Psalter_Pahlavi # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW +10B99..10B9C ; Psalter_Pahlavi # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT +10BA9..10BAF ; Psalter_Pahlavi # No [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED + +# Total code points: 29 + +# ================================================ + +11580..115AE ; Siddham # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA +115AF..115B1 ; Siddham # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II +115B2..115B5 ; Siddham # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR +115B8..115BB ; Siddham # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU +115BC..115BD ; Siddham # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA +115BE ; Siddham # Mc SIDDHAM SIGN VISARGA +115BF..115C0 ; Siddham # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA +115C1..115C9 ; Siddham # Po [9] SIDDHAM SIGN SIDDHAM..SIDDHAM END OF TEXT MARK + +# Total code points: 72 + +# ================================================ + +112B0..112DE ; Khudawadi # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA +112DF ; Khudawadi # Mn KHUDAWADI SIGN ANUSVARA +112E0..112E2 ; Khudawadi # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II +112E3..112EA ; Khudawadi # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA +112F0..112F9 ; Khudawadi # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE + +# Total code points: 69 + +# ================================================ + +11480..114AF ; Tirhuta # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA +114B0..114B2 ; Tirhuta # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II +114B3..114B8 ; Tirhuta # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL +114B9 ; Tirhuta # Mc TIRHUTA VOWEL SIGN E +114BA ; Tirhuta # Mn TIRHUTA VOWEL SIGN SHORT E +114BB..114BE ; Tirhuta # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU +114BF..114C0 ; Tirhuta # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA +114C1 ; Tirhuta # Mc TIRHUTA SIGN VISARGA +114C2..114C3 ; Tirhuta # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA +114C4..114C5 ; Tirhuta # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG +114C6 ; Tirhuta # Po TIRHUTA ABBREVIATION SIGN +114C7 ; Tirhuta # Lo TIRHUTA OM +114D0..114D9 ; Tirhuta # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE + +# Total code points: 82 + +# ================================================ + +118A0..118DF ; Warang_Citi # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO +118E0..118E9 ; Warang_Citi # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE +118EA..118F2 ; Warang_Citi # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY +118FF ; Warang_Citi # Lo WARANG CITI OM + +# Total code points: 84 + # EOF diff --git a/jdk/make/data/unicodedata/SpecialCasing.txt b/jdk/make/data/unicodedata/SpecialCasing.txt index 994043f01bf..43645bd2d10 100644 --- a/jdk/make/data/unicodedata/SpecialCasing.txt +++ b/jdk/make/data/unicodedata/SpecialCasing.txt @@ -1,18 +1,25 @@ -# SpecialCasing-6.2.0.txt -# Date: 2012-05-23, 20:35:15 GMT [MD] +# SpecialCasing-7.0.0.txt +# Date: 2014-03-18, 07:18:02 GMT [MD] # # Unicode Character Database -# Copyright (c) 1991-2012 Unicode, Inc. +# Copyright (c) 1991-2014 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # For documentation, see http://www.unicode.org/reports/tr44/ # -# Special Casing Properties +# Special Casing # -# This file is a supplement to the UnicodeData file. -# It contains additional information about the casing of Unicode characters. -# (For compatibility, the UnicodeData.txt file only contains case mappings for -# characters where they are 1-1, and independent of context and language. -# For more information, see the discussion of Case Mappings in the Unicode Standard. +# This file is a supplement to the UnicodeData.txt file. It does not define any +# properties, but rather provides additional information about the casing of +# Unicode characters, for situations when casing incurs a change in string length +# or is dependent on context or locale. For compatibility, the UnicodeData.txt +# file only contains simple case mappings for characters where they are one-to-one +# and independent of context and language. The data in this file, combined with +# the simple case mappings in UnicodeData.txt, defines the full case mappings +# Lowercase_Mapping (lc), Titlecase_Mapping (tc), and Uppercase_Mapping (uc). +# +# Note that the preferred mechanism for defining tailored casing operations is +# the Unicode Common Locale Data Repository (CLDR). For more information, see the +# discussion of case mappings and case algorithms in the Unicode Standard. # # All code points not listed in this file that do not have a simple case mappings # in UnicodeData.txt map to themselves. @@ -21,16 +28,17 @@ # ================================================================================ # The entries in this file are in the following machine-readable format: # -# ; ; ; <upper> ; (<condition_list> ;)? # <comment> +# <code>; <lower>; <title>; <upper>; (<condition_list>;)? # <comment> # -# <code>, <lower>, <title>, and <upper> provide character values in hex. If there is more -# than one character, they are separated by spaces. Other than as used to separate -# elements, spaces are to be ignored. +# <code>, <lower>, <title>, and <upper> provide the respective full case mappings +# of <code>, expressed as character values in hex. If there is more than one character, +# they are separated by spaces. Other than as used to separate elements, spaces are +# to be ignored. # # The <condition_list> is optional. Where present, it consists of one or more language IDs -# or contexts, separated by spaces. In these conditions: +# or casing contexts, separated by spaces. In these conditions: # - A condition list overrides the normal behavior if all of the listed conditions are true. -# - The context is always the context of the characters in the original string, +# - The casing context is always the context of the characters in the original string, # NOT in the resulting string. # - Case distinctions in the condition list are not significant. # - Conditions preceded by "Not_" represent the negation of the condition. @@ -38,18 +46,14 @@ # # A language ID is defined by BCP 47, with '-' and '_' treated equivalently. # -# A context for a character C is defined by Section 3.13 Default Case -# Operations, of The Unicode Standard, Version 5.0. -# (This is identical to the context defined by Unicode 4.1.0, -# as specified in http://www.unicode.org/versions/Unicode4.1.0/) +# A casing context for a character is defined by Section 3.13 Default Case Algorithms +# of The Unicode Standard. # # Parsers of this file must be prepared to deal with future additions to this format: # * Additional contexts # * Additional fields # ================================================================================ -# @missing: 0000..10FFFF; <slc>; <stc>; <suc>; - # ================================================================================ # Unconditional mappings # ================================================================================ @@ -114,7 +118,7 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH # This process can be achieved by first transforming the text to NFC before casing. # E.g. <alpha><iota_subscript><acute> is uppercased to <ALPHA><acute><IOTA> -# The following cases are already in the UnicodeData file, so are only commented here. +# The following cases are already in the UnicodeData.txt file, so are only commented here. # 0345; 0345; 0345; 0399; # COMBINING GREEK YPOGEGRAMMENI @@ -205,7 +209,7 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH 03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA -# Note: the following cases for non-final are already in the UnicodeData file. +# Note: the following cases for non-final are already in the UnicodeData.txt file. # 03A3; 03C3; 03A3; 03A3; # GREEK CAPITAL LETTER SIGMA # 03C3; 03C3; 03A3; 03A3; # GREEK SMALL LETTER SIGMA @@ -268,7 +272,7 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH 0069; 0069; 0130; 0130; tr; # LATIN SMALL LETTER I 0069; 0069; 0130; 0130; az; # LATIN SMALL LETTER I -# Note: the following case is already in the UnicodeData file. +# Note: the following case is already in the UnicodeData.txt file. # 0131; 0131; 0049; 0049; tr; # LATIN SMALL LETTER DOTLESS I diff --git a/jdk/make/data/unicodedata/UnicodeData.txt b/jdk/make/data/unicodedata/UnicodeData.txt index 086379eb4f3..31c8a7eaa04 100644 --- a/jdk/make/data/unicodedata/UnicodeData.txt +++ b/jdk/make/data/unicodedata/UnicodeData.txt @@ -602,12 +602,12 @@ 0259;LATIN SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;018F;;018F 025A;LATIN SMALL LETTER SCHWA WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCHWA HOOK;;;; 025B;LATIN SMALL LETTER OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER EPSILON;;0190;;0190 -025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;;; +025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;A7AB;;A7AB 025D;LATIN SMALL LETTER REVERSED OPEN E WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON HOOK;;;; 025E;LATIN SMALL LETTER CLOSED REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED REVERSED EPSILON;;;; 025F;LATIN SMALL LETTER DOTLESS J WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR;;;; 0260;LATIN SMALL LETTER G WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER G HOOK;;0193;;0193 -0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;;; +0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;A7AC;;A7AC 0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;; 0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194 0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;;; @@ -618,7 +618,7 @@ 0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196 026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;;; 026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;2C62;;2C62 -026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;;; +026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;A7AD;;A7AD 026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;; 026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;; 026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C @@ -645,7 +645,7 @@ 0284;LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR HOOK;;;; 0285;LATIN SMALL LETTER SQUAT REVERSED ESH;Ll;0;L;;;;;N;;;;; 0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;; -0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;;; +0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;A7B1;;A7B1 0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE 0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;0244;;0244 028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1 @@ -668,7 +668,7 @@ 029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;; 029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;; 029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;;; -029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;;; +029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;A7B0;;A7B0 029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;; 02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;; 02A1;LATIN LETTER GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER GLOTTAL STOP BAR;;;; @@ -891,6 +891,7 @@ 037C;GREEK SMALL DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FE;;03FE 037D;GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FF;;03FF 037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;;;; +037F;GREEK CAPITAL LETTER YOT;Lu;0;L;;;;;N;;;;03F3; 0384;GREEK TONOS;Sk;0;ON;<compat> 0020 0301;;;;N;GREEK SPACING TONOS;;;; 0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;; 0386;GREEK CAPITAL LETTER ALPHA WITH TONOS;Lu;0;L;0391 0301;;;;N;GREEK CAPITAL LETTER ALPHA TONOS;;;03AC; @@ -999,7 +1000,7 @@ 03F0;GREEK KAPPA SYMBOL;Ll;0;L;<compat> 03BA;;;;N;GREEK SMALL LETTER SCRIPT KAPPA;;039A;;039A 03F1;GREEK RHO SYMBOL;Ll;0;L;<compat> 03C1;;;;N;GREEK SMALL LETTER TAILED RHO;;03A1;;03A1 03F2;GREEK LUNATE SIGMA SYMBOL;Ll;0;L;<compat> 03C2;;;;N;GREEK SMALL LETTER LUNATE SIGMA;;03F9;;03F9 -03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;;; +03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;037F;;037F 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8; 03F5;GREEK LUNATE EPSILON SYMBOL;Ll;0;L;<compat> 03B5;;;;N;;;0395;;0395 03F6;GREEK REVERSED LUNATE EPSILON SYMBOL;Sm;0;ON;;;;;N;;;;; @@ -1308,6 +1309,14 @@ 0525;CYRILLIC SMALL LETTER PE WITH DESCENDER;Ll;0;L;;;;;N;;;0524;;0524 0526;CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER;Lu;0;L;;;;;N;;;;0527; 0527;CYRILLIC SMALL LETTER SHHA WITH DESCENDER;Ll;0;L;;;;;N;;;0526;;0526 +0528;CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK;Lu;0;L;;;;;N;;;;0529; +0529;CYRILLIC SMALL LETTER EN WITH LEFT HOOK;Ll;0;L;;;;;N;;;0528;;0528 +052A;CYRILLIC CAPITAL LETTER DZZHE;Lu;0;L;;;;;N;;;;052B; +052B;CYRILLIC SMALL LETTER DZZHE;Ll;0;L;;;;;N;;;052A;;052A +052C;CYRILLIC CAPITAL LETTER DCHE;Lu;0;L;;;;;N;;;;052D; +052D;CYRILLIC SMALL LETTER DCHE;Ll;0;L;;;;;N;;;052C;;052C +052E;CYRILLIC CAPITAL LETTER EL WITH DESCENDER;Lu;0;L;;;;;N;;;;052F; +052F;CYRILLIC SMALL LETTER EL WITH DESCENDER;Ll;0;L;;;;;N;;;052E;;052E 0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561; 0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562; 0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563; @@ -1394,6 +1403,8 @@ 0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L;<compat> 0565 0582;;;;N;;;;; 0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;; 058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;; +058D;RIGHT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;; +058E;LEFT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;; 058F;ARMENIAN DRAM SIGN;Sc;0;ET;;;;;N;;;;; 0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;; 0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;; @@ -1487,6 +1498,7 @@ 0602;ARABIC FOOTNOTE MARKER;Cf;0;AN;;;;;N;;;;; 0603;ARABIC SIGN SAFHA;Cf;0;AN;;;;;N;;;;; 0604;ARABIC SIGN SAMVAT;Cf;0;AN;;;;;N;;;;; +0605;ARABIC NUMBER MARK ABOVE;Cf;0;AN;;;;;N;;;;; 0606;ARABIC-INDIC CUBE ROOT;Sm;0;ON;;;;;N;;;;; 0607;ARABIC-INDIC FOURTH ROOT;Sm;0;ON;;;;;N;;;;; 0608;ARABIC RAY;Sm;0;AL;;;;;N;;;;; @@ -1509,6 +1521,7 @@ 0619;ARABIC SMALL DAMMA;Mn;31;NSM;;;;;N;;;;; 061A;ARABIC SMALL KASRA;Mn;32;NSM;;;;;N;;;;; 061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;; +061C;ARABIC LETTER MARK;Cf;0;AL;;;;;N;;;;; 061E;ARABIC TRIPLE DOT PUNCTUATION MARK;Po;0;AL;;;;;N;;;;; 061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;; 0620;ARABIC LETTER KASHMIRI YEH;Lo;0;AL;;;;;N;;;;; @@ -2060,6 +2073,7 @@ 085B;MANDAIC GEMINATION MARK;Mn;220;NSM;;;;;N;;;;; 085E;MANDAIC PUNCTUATION;Po;0;R;;;;;N;;;;; 08A0;ARABIC LETTER BEH WITH SMALL V BELOW;Lo;0;AL;;;;;N;;;;; +08A1;ARABIC LETTER BEH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;; 08A2;ARABIC LETTER JEEM WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 08A3;ARABIC LETTER TAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 08A4;ARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; @@ -2071,6 +2085,12 @@ 08AA;ARABIC LETTER REH WITH LOOP;Lo;0;AL;;;;;N;;;;; 08AB;ARABIC LETTER WAW WITH DOT WITHIN;Lo;0;AL;;;;;N;;;;; 08AC;ARABIC LETTER ROHINGYA YEH;Lo;0;AL;;;;;N;;;;; +08AD;ARABIC LETTER LOW ALEF;Lo;0;AL;;;;;N;;;;; +08AE;ARABIC LETTER DAL WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +08AF;ARABIC LETTER SAD WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +08B0;ARABIC LETTER GAF WITH INVERTED STROKE;Lo;0;AL;;;;;N;;;;; +08B1;ARABIC LETTER STRAIGHT WAW;Lo;0;AL;;;;;N;;;;; +08B2;ARABIC LETTER ZAIN WITH INVERTED V ABOVE;Lo;0;AL;;;;;N;;;;; 08E4;ARABIC CURLY FATHA;Mn;230;NSM;;;;;N;;;;; 08E5;ARABIC CURLY DAMMA;Mn;230;NSM;;;;;N;;;;; 08E6;ARABIC CURLY KASRA;Mn;220;NSM;;;;;N;;;;; @@ -2098,6 +2118,7 @@ 08FC;ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;; 08FD;ARABIC RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;; 08FE;ARABIC DAMMA WITH DOT;Mn;230;NSM;;;;;N;;;;; +08FF;ARABIC MARK SIDEWAYS NOON GHUNNA;Mn;230;NSM;;;;;N;;;;; 0900;DEVANAGARI SIGN INVERTED CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; @@ -2218,6 +2239,7 @@ 0975;DEVANAGARI LETTER AW;Lo;0;L;;;;;N;;;;; 0976;DEVANAGARI LETTER UE;Lo;0;L;;;;;N;;;;; 0977;DEVANAGARI LETTER UUE;Lo;0;L;;;;;N;;;;; +0978;DEVANAGARI LETTER MARWARI DDA;Lo;0;L;;;;;N;;;;; 0979;DEVANAGARI LETTER ZHA;Lo;0;L;;;;;N;;;;; 097A;DEVANAGARI LETTER HEAVY YA;Lo;0;L;;;;;N;;;;; 097B;DEVANAGARI LETTER GGA;Lo;0;L;;;;;N;;;;; @@ -2225,6 +2247,7 @@ 097D;DEVANAGARI LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;; 097E;DEVANAGARI LETTER DDDA;Lo;0;L;;;;;N;;;;; 097F;DEVANAGARI LETTER BBA;Lo;0;L;;;;;N;;;;; +0980;BENGALI ANJI;Lo;0;L;;;;;N;;;;; 0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -2642,6 +2665,7 @@ 0BF8;TAMIL AS ABOVE SIGN;So;0;ON;;;;;N;;;;; 0BF9;TAMIL RUPEE SIGN;Sc;0;ET;;;;;N;;;;; 0BFA;TAMIL NUMBER SIGN;So;0;ON;;;;;N;;;;; +0C00;TELUGU SIGN COMBINING CANDRABINDU ABOVE;Mn;0;NSM;;;;;N;;;;; 0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;; 0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -2689,6 +2713,7 @@ 0C31;TELUGU LETTER RRA;Lo;0;L;;;;;N;;;;; 0C32;TELUGU LETTER LA;Lo;0;L;;;;;N;;;;; 0C33;TELUGU LETTER LLA;Lo;0;L;;;;;N;;;;; +0C34;TELUGU LETTER LLLA;Lo;0;L;;;;;N;;;;; 0C35;TELUGU LETTER VA;Lo;0;L;;;;;N;;;;; 0C36;TELUGU LETTER SHA;Lo;0;L;;;;;N;;;;; 0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;; @@ -2735,6 +2760,7 @@ 0C7D;TELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOUR;No;0;ON;;;;2;N;;;;; 0C7E;TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR;No;0;ON;;;;3;N;;;;; 0C7F;TELUGU SIGN TUUMU;So;0;L;;;;;N;;;;; +0C81;KANNADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;; @@ -2821,6 +2847,7 @@ 0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0CF1;KANNADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; 0CF2;KANNADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +0D01;MALAYALAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;; @@ -2996,6 +3023,16 @@ 0DDD;SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA;Mc;0;L;0DDC 0DCA;;;;N;;;;; 0DDE;SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA;Mc;0;L;0DD9 0DDF;;;;N;;;;; 0DDF;SINHALA VOWEL SIGN GAYANUKITTA;Mc;0;L;;;;;N;;;;; +0DE6;SINHALA LITH DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0DE7;SINHALA LITH DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0DE8;SINHALA LITH DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0DE9;SINHALA LITH DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0DEA;SINHALA LITH DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0DEB;SINHALA LITH DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0DEC;SINHALA LITH DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0DED;SINHALA LITH DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0DEE;SINHALA LITH DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0DEF;SINHALA LITH DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0DF2;SINHALA VOWEL SIGN DIGA GAETTA-PILLA;Mc;0;L;;;;;N;;;;; 0DF3;SINHALA VOWEL SIGN DIGA GAYANUKITTA;Mc;0;L;;;;;N;;;;; 0DF4;SINHALA PUNCTUATION KUNDDALIYA;Po;0;L;;;;;N;;;;; @@ -5087,6 +5124,14 @@ 16EE;RUNIC ARLAUG SYMBOL;Nl;0;L;;;;17;N;;;;; 16EF;RUNIC TVIMADUR SYMBOL;Nl;0;L;;;;18;N;;;;; 16F0;RUNIC BELGTHOR SYMBOL;Nl;0;L;;;;19;N;;;;; +16F1;RUNIC LETTER K;Lo;0;L;;;;;N;;;;; +16F2;RUNIC LETTER SH;Lo;0;L;;;;;N;;;;; +16F3;RUNIC LETTER OO;Lo;0;L;;;;;N;;;;; +16F4;RUNIC LETTER FRANKS CASKET OS;Lo;0;L;;;;;N;;;;; +16F5;RUNIC LETTER FRANKS CASKET IS;Lo;0;L;;;;;N;;;;; +16F6;RUNIC LETTER FRANKS CASKET EH;Lo;0;L;;;;;N;;;;; +16F7;RUNIC LETTER FRANKS CASKET AC;Lo;0;L;;;;;N;;;;; +16F8;RUNIC LETTER FRANKS CASKET AESC;Lo;0;L;;;;;N;;;;; 1700;TAGALOG LETTER A;Lo;0;L;;;;;N;;;;; 1701;TAGALOG LETTER I;Lo;0;L;;;;;N;;;;; 1702;TAGALOG LETTER U;Lo;0;L;;;;;N;;;;; @@ -5296,7 +5341,7 @@ 180B;MONGOLIAN FREE VARIATION SELECTOR ONE;Mn;0;NSM;;;;;N;;;;; 180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Mn;0;NSM;;;;;N;;;;; 180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Mn;0;NSM;;;;;N;;;;; -180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;; +180E;MONGOLIAN VOWEL SEPARATOR;Cf;0;BN;;;;;N;;;;; 1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -5537,6 +5582,8 @@ 191A;LIMBU LETTER SSA;Lo;0;L;;;;;N;;;;; 191B;LIMBU LETTER SA;Lo;0;L;;;;;N;;;;; 191C;LIMBU LETTER HA;Lo;0;L;;;;;N;;;;; +191D;LIMBU LETTER GYAN;Lo;0;L;;;;;N;;;;; +191E;LIMBU LETTER TRA;Lo;0;L;;;;;N;;;;; 1920;LIMBU VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;; 1921;LIMBU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 1922;LIMBU VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; @@ -5751,7 +5798,7 @@ 1A18;BUGINESE VOWEL SIGN U;Mn;220;NSM;;;;;N;;;;; 1A19;BUGINESE VOWEL SIGN E;Mc;0;L;;;;;N;;;;; 1A1A;BUGINESE VOWEL SIGN O;Mc;0;L;;;;;N;;;;; -1A1B;BUGINESE VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; +1A1B;BUGINESE VOWEL SIGN AE;Mn;0;NSM;;;;;N;;;;; 1A1E;BUGINESE PALLAWA;Po;0;L;;;;;N;;;;; 1A1F;BUGINESE END OF SECTION;Po;0;L;;;;;N;;;;; 1A20;TAI THAM LETTER HIGH KA;Lo;0;L;;;;;N;;;;; @@ -5881,6 +5928,21 @@ 1AAB;TAI THAM SIGN SATKAANKUU;Po;0;L;;;;;N;;;;; 1AAC;TAI THAM SIGN HANG;Po;0;L;;;;;N;;;;; 1AAD;TAI THAM SIGN CAANG;Po;0;L;;;;;N;;;;; +1AB0;COMBINING DOUBLED CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;;;;; +1AB1;COMBINING DIAERESIS-RING;Mn;230;NSM;;;;;N;;;;; +1AB2;COMBINING INFINITY;Mn;230;NSM;;;;;N;;;;; +1AB3;COMBINING DOWNWARDS ARROW;Mn;230;NSM;;;;;N;;;;; +1AB4;COMBINING TRIPLE DOT;Mn;230;NSM;;;;;N;;;;; +1AB5;COMBINING X-X BELOW;Mn;220;NSM;;;;;N;;;;; +1AB6;COMBINING WIGGLY LINE BELOW;Mn;220;NSM;;;;;N;;;;; +1AB7;COMBINING OPEN MARK BELOW;Mn;220;NSM;;;;;N;;;;; +1AB8;COMBINING DOUBLE OPEN MARK BELOW;Mn;220;NSM;;;;;N;;;;; +1AB9;COMBINING LIGHT CENTRALIZATION STROKE BELOW;Mn;220;NSM;;;;;N;;;;; +1ABA;COMBINING STRONG CENTRALIZATION STROKE BELOW;Mn;220;NSM;;;;;N;;;;; +1ABB;COMBINING PARENTHESES ABOVE;Mn;230;NSM;;;;;N;;;;; +1ABC;COMBINING DOUBLE PARENTHESES ABOVE;Mn;230;NSM;;;;;N;;;;; +1ABD;COMBINING PARENTHESES BELOW;Mn;220;NSM;;;;;N;;;;; +1ABE;COMBINING PARENTHESES OVERLAY;Me;0;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;;;;; @@ -6046,8 +6108,8 @@ 1BA9;SUNDANESE VOWEL SIGN PANEULEUNG;Mn;0;NSM;;;;;N;;;;; 1BAA;SUNDANESE SIGN PAMAAEH;Mc;9;L;;;;;N;;;;; 1BAB;SUNDANESE SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; -1BAC;SUNDANESE CONSONANT SIGN PASANGAN MA;Mc;0;L;;;;;N;;;;; -1BAD;SUNDANESE CONSONANT SIGN PASANGAN WA;Mc;0;L;;;;;N;;;;; +1BAC;SUNDANESE CONSONANT SIGN PASANGAN MA;Mn;0;NSM;;;;;N;;;;; +1BAD;SUNDANESE CONSONANT SIGN PASANGAN WA;Mn;0;NSM;;;;;N;;;;; 1BAE;SUNDANESE LETTER KHA;Lo;0;L;;;;;N;;;;; 1BAF;SUNDANESE LETTER SYA;Lo;0;L;;;;;N;;;;; 1BB0;SUNDANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; @@ -6291,6 +6353,8 @@ 1CF4;VEDIC TONE CANDRA ABOVE;Mn;230;NSM;;;;;N;;;;; 1CF5;VEDIC SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; 1CF6;VEDIC SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +1CF8;VEDIC TONE RING ABOVE;Mn;230;NSM;;;;;N;;;;; +1CF9;VEDIC TONE DOUBLE RING ABOVE;Mn;230;NSM;;;;;N;;;;; 1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;; 1D01;LATIN LETTER SMALL CAPITAL AE;Ll;0;L;;;;;N;;;;; 1D02;LATIN SMALL LETTER TURNED AE;Ll;0;L;;;;;N;;;;; @@ -6522,6 +6586,21 @@ 1DE4;COMBINING LATIN SMALL LETTER S;Mn;230;NSM;;;;;N;;;;; 1DE5;COMBINING LATIN SMALL LETTER LONG S;Mn;230;NSM;;;;;N;;;;; 1DE6;COMBINING LATIN SMALL LETTER Z;Mn;230;NSM;;;;;N;;;;; +1DE7;COMBINING LATIN SMALL LETTER ALPHA;Mn;230;NSM;;;;;N;;;;; +1DE8;COMBINING LATIN SMALL LETTER B;Mn;230;NSM;;;;;N;;;;; +1DE9;COMBINING LATIN SMALL LETTER BETA;Mn;230;NSM;;;;;N;;;;; +1DEA;COMBINING LATIN SMALL LETTER SCHWA;Mn;230;NSM;;;;;N;;;;; +1DEB;COMBINING LATIN SMALL LETTER F;Mn;230;NSM;;;;;N;;;;; +1DEC;COMBINING LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE;Mn;230;NSM;;;;;N;;;;; +1DED;COMBINING LATIN SMALL LETTER O WITH LIGHT CENTRALIZATION STROKE;Mn;230;NSM;;;;;N;;;;; +1DEE;COMBINING LATIN SMALL LETTER P;Mn;230;NSM;;;;;N;;;;; +1DEF;COMBINING LATIN SMALL LETTER ESH;Mn;230;NSM;;;;;N;;;;; +1DF0;COMBINING LATIN SMALL LETTER U WITH LIGHT CENTRALIZATION STROKE;Mn;230;NSM;;;;;N;;;;; +1DF1;COMBINING LATIN SMALL LETTER W;Mn;230;NSM;;;;;N;;;;; +1DF2;COMBINING LATIN SMALL LETTER A WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; +1DF3;COMBINING LATIN SMALL LETTER O WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; +1DF4;COMBINING LATIN SMALL LETTER U WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; +1DF5;COMBINING UP TACK ABOVE;Mn;230;NSM;;;;;N;;;;; 1DFC;COMBINING DOUBLE INVERTED BREVE BELOW;Mn;233;NSM;;;;;N;;;;; 1DFD;COMBINING ALMOST EQUAL TO BELOW;Mn;220;NSM;;;;;N;;;;; 1DFE;COMBINING LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; @@ -7116,6 +7195,10 @@ 2062;INVISIBLE TIMES;Cf;0;BN;;;;;N;;;;; 2063;INVISIBLE SEPARATOR;Cf;0;BN;;;;;N;;;;; 2064;INVISIBLE PLUS;Cf;0;BN;;;;;N;;;;; +2066;LEFT-TO-RIGHT ISOLATE;Cf;0;LRI;;;;;N;;;;; +2067;RIGHT-TO-LEFT ISOLATE;Cf;0;RLI;;;;;N;;;;; +2068;FIRST STRONG ISOLATE;Cf;0;FSI;;;;;N;;;;; +2069;POP DIRECTIONAL ISOLATE;Cf;0;PDI;;;;;N;;;;; 206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; 206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; 206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; @@ -7191,6 +7274,9 @@ 20B8;TENGE SIGN;Sc;0;ET;;;;;N;;;;; 20B9;INDIAN RUPEE SIGN;Sc;0;ET;;;;;N;;;;; 20BA;TURKISH LIRA SIGN;Sc;0;ET;;;;;N;;;;; +20BB;NORDIC MARK SIGN;Sc;0;ET;;;;;N;;;;; +20BC;MANAT SIGN;Sc;0;ET;;;;;N;;;;; +20BD;RUBLE 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;;;; @@ -7738,10 +7824,10 @@ 2305;PROJECTIVE;So;0;ON;;;;;N;;;;; 2306;PERSPECTIVE;So;0;ON;;;;;N;;;;; 2307;WAVY LINE;So;0;ON;;;;;N;;;;; -2308;LEFT CEILING;Sm;0;ON;;;;;Y;;;;; -2309;RIGHT CEILING;Sm;0;ON;;;;;Y;;;;; -230A;LEFT FLOOR;Sm;0;ON;;;;;Y;;;;; -230B;RIGHT FLOOR;Sm;0;ON;;;;;Y;;;;; +2308;LEFT CEILING;Ps;0;ON;;;;;Y;;;;; +2309;RIGHT CEILING;Pe;0;ON;;;;;Y;;;;; +230A;LEFT FLOOR;Ps;0;ON;;;;;Y;;;;; +230B;RIGHT FLOOR;Pe;0;ON;;;;;Y;;;;; 230C;BOTTOM RIGHT CROP;So;0;ON;;;;;N;;;;; 230D;BOTTOM LEFT CROP;So;0;ON;;;;;N;;;;; 230E;TOP RIGHT CROP;So;0;ON;;;;;N;;;;; @@ -7974,6 +8060,13 @@ 23F1;STOPWATCH;So;0;ON;;;;;N;;;;; 23F2;TIMER CLOCK;So;0;ON;;;;;N;;;;; 23F3;HOURGLASS WITH FLOWING SAND;So;0;ON;;;;;N;;;;; +23F4;BLACK MEDIUM LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +23F5;BLACK MEDIUM RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +23F6;BLACK MEDIUM UP-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +23F7;BLACK MEDIUM DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;;;;; +23F8;DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;; +23F9;BLACK SQUARE FOR STOP;So;0;ON;;;;;N;;;;; +23FA;BLACK CIRCLE FOR RECORD;So;0;ON;;;;;N;;;;; 2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;; 2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;; 2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;; @@ -8696,6 +8789,7 @@ 26FD;FUEL PUMP;So;0;ON;;;;;N;;;;; 26FE;CUP ON BLACK SQUARE;So;0;ON;;;;;N;;;;; 26FF;WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE;So;0;ON;;;;;N;;;;; +2700;BLACK SAFETY SCISSORS;So;0;ON;;;;;N;;;;; 2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;; 2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;; 2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;; @@ -9796,6 +9890,9 @@ 2B4A;LEFTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; 2B4B;LEFTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; 2B4C;RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; +2B4D;DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW;So;0;ON;;;;;N;;;;; +2B4E;SHORT SLANTED NORTH ARROW;So;0;ON;;;;;N;;;;; +2B4F;SHORT BACKSLANTED SOUTH ARROW;So;0;ON;;;;;N;;;;; 2B50;WHITE MEDIUM STAR;So;0;ON;;;;;N;;;;; 2B51;BLACK SMALL STAR;So;0;ON;;;;;N;;;;; 2B52;WHITE SMALL STAR;So;0;ON;;;;;N;;;;; @@ -9806,6 +9903,118 @@ 2B57;HEAVY CIRCLE WITH CIRCLE INSIDE;So;0;ON;;;;;N;;;;; 2B58;HEAVY CIRCLE;So;0;ON;;;;;N;;;;; 2B59;HEAVY CIRCLED SALTIRE;So;0;ON;;;;;N;;;;; +2B5A;SLANTED NORTH ARROW WITH HOOKED HEAD;So;0;ON;;;;;N;;;;; +2B5B;BACKSLANTED SOUTH ARROW WITH HOOKED TAIL;So;0;ON;;;;;N;;;;; +2B5C;SLANTED NORTH ARROW WITH HORIZONTAL TAIL;So;0;ON;;;;;N;;;;; +2B5D;BACKSLANTED SOUTH ARROW WITH HORIZONTAL TAIL;So;0;ON;;;;;N;;;;; +2B5E;BENT ARROW POINTING DOWNWARDS THEN NORTH EAST;So;0;ON;;;;;N;;;;; +2B5F;SHORT BENT ARROW POINTING DOWNWARDS THEN NORTH EAST;So;0;ON;;;;;N;;;;; +2B60;LEFTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B61;UPWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B62;RIGHTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B63;DOWNWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B64;LEFT RIGHT TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B65;UP DOWN TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B66;NORTH WEST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B67;NORTH EAST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B68;SOUTH EAST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B69;SOUTH WEST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B6A;LEFTWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; +2B6B;UPWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; +2B6C;RIGHTWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; +2B6D;DOWNWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;; +2B6E;CLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; +2B6F;ANTICLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; +2B70;LEFTWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B71;UPWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B72;RIGHTWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B73;DOWNWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B76;NORTH WEST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B77;NORTH EAST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B78;SOUTH EAST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B79;SOUTH WEST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;; +2B7A;LEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; +2B7B;UPWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; +2B7C;RIGHTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; +2B7D;DOWNWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;; +2B7E;HORIZONTAL TAB KEY;So;0;ON;;;;;N;;;;; +2B7F;VERTICAL TAB KEY;So;0;ON;;;;;N;;;;; +2B80;LEFTWARDS TRIANGLE-HEADED ARROW OVER RIGHTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B81;UPWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF DOWNWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B82;RIGHTWARDS TRIANGLE-HEADED ARROW OVER LEFTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B83;DOWNWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF UPWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;; +2B84;LEFTWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; +2B85;UPWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; +2B86;RIGHTWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; +2B87;DOWNWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;; +2B88;LEFTWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; +2B89;UPWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; +2B8A;RIGHTWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; +2B8B;DOWNWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;; +2B8C;ANTICLOCKWISE TRIANGLE-HEADED RIGHT U-SHAPED ARROW;So;0;ON;;;;;N;;;;; +2B8D;ANTICLOCKWISE TRIANGLE-HEADED BOTTOM U-SHAPED ARROW;So;0;ON;;;;;N;;;;; +2B8E;ANTICLOCKWISE TRIANGLE-HEADED LEFT U-SHAPED ARROW;So;0;ON;;;;;N;;;;; +2B8F;ANTICLOCKWISE TRIANGLE-HEADED TOP U-SHAPED ARROW;So;0;ON;;;;;N;;;;; +2B90;RETURN LEFT;So;0;ON;;;;;N;;;;; +2B91;RETURN RIGHT;So;0;ON;;;;;N;;;;; +2B92;NEWLINE LEFT;So;0;ON;;;;;N;;;;; +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;;;;; +2B98;THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B99;THREE-D RIGHT-LIGHTED UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9A;THREE-D TOP-LIGHTED RIGHTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9B;THREE-D LEFT-LIGHTED DOWNWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9C;BLACK LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9D;BLACK UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9E;BLACK RIGHTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2B9F;BLACK DOWNWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +2BA0;DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS;So;0;ON;;;;;N;;;;; +2BA1;DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS;So;0;ON;;;;;N;;;;; +2BA2;UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS;So;0;ON;;;;;N;;;;; +2BA3;UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS;So;0;ON;;;;;N;;;;; +2BA4;LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS;So;0;ON;;;;;N;;;;; +2BA5;RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS;So;0;ON;;;;;N;;;;; +2BA6;LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS;So;0;ON;;;;;N;;;;; +2BA7;RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS;So;0;ON;;;;;N;;;;; +2BA8;BLACK CURVED DOWNWARDS AND LEFTWARDS ARROW;So;0;ON;;;;;N;;;;; +2BA9;BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAA;BLACK CURVED UPWARDS AND LEFTWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAB;BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAC;BLACK CURVED LEFTWARDS AND UPWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAD;BLACK CURVED RIGHTWARDS AND UPWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAE;BLACK CURVED LEFTWARDS AND DOWNWARDS ARROW;So;0;ON;;;;;N;;;;; +2BAF;BLACK CURVED RIGHTWARDS AND DOWNWARDS ARROW;So;0;ON;;;;;N;;;;; +2BB0;RIBBON ARROW DOWN LEFT;So;0;ON;;;;;N;;;;; +2BB1;RIBBON ARROW DOWN RIGHT;So;0;ON;;;;;N;;;;; +2BB2;RIBBON ARROW UP LEFT;So;0;ON;;;;;N;;;;; +2BB3;RIBBON ARROW UP RIGHT;So;0;ON;;;;;N;;;;; +2BB4;RIBBON ARROW LEFT UP;So;0;ON;;;;;N;;;;; +2BB5;RIBBON ARROW RIGHT UP;So;0;ON;;;;;N;;;;; +2BB6;RIBBON ARROW LEFT DOWN;So;0;ON;;;;;N;;;;; +2BB7;RIBBON ARROW RIGHT DOWN;So;0;ON;;;;;N;;;;; +2BB8;UPWARDS WHITE ARROW FROM BAR WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;; +2BB9;UP ARROWHEAD IN A RECTANGLE BOX;So;0;ON;;;;;N;;;;; +2BBD;BALLOT BOX WITH LIGHT X;So;0;ON;;;;;N;;;;; +2BBE;CIRCLED X;So;0;ON;;;;;N;;;;; +2BBF;CIRCLED BOLD X;So;0;ON;;;;;N;;;;; +2BC0;BLACK SQUARE CENTRED;So;0;ON;;;;;N;;;;; +2BC1;BLACK DIAMOND CENTRED;So;0;ON;;;;;N;;;;; +2BC2;TURNED BLACK PENTAGON;So;0;ON;;;;;N;;;;; +2BC3;HORIZONTAL BLACK OCTAGON;So;0;ON;;;;;N;;;;; +2BC4;BLACK OCTAGON;So;0;ON;;;;;N;;;;; +2BC5;BLACK MEDIUM UP-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; +2BC6;BLACK MEDIUM DOWN-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; +2BC7;BLACK MEDIUM LEFT-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; +2BC8;BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;; +2BCA;TOP HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +2BCB;BOTTOM HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +2BCC;LIGHT FOUR POINTED BLACK CUSP;So;0;ON;;;;;N;;;;; +2BCD;ROTATED LIGHT FOUR POINTED BLACK CUSP;So;0;ON;;;;;N;;;;; +2BCE;WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;; +2BCF;ROTATED WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;; +2BD0;SQUARE POSITION INDICATOR;So;0;ON;;;;;N;;;;; +2BD1;UNCERTAINTY SIGN;So;0;ON;;;;;N;;;;; 2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30; 2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31; 2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32; @@ -10325,6 +10534,13 @@ 2E39;TOP HALF SECTION SIGN;Po;0;ON;;;;;N;;;;; 2E3A;TWO-EM DASH;Pd;0;ON;;;;;N;;;;; 2E3B;THREE-EM DASH;Pd;0;ON;;;;;N;;;;; +2E3C;STENOGRAPHIC FULL STOP;Po;0;ON;;;;;N;;;;; +2E3D;VERTICAL SIX DOTS;Po;0;ON;;;;;N;;;;; +2E3E;WIGGLY VERTICAL LINE;Po;0;ON;;;;;N;;;;; +2E3F;CAPITULUM;Po;0;ON;;;;;N;;;;; +2E40;DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;; +2E41;REVERSED COMMA;Po;0;ON;;;;;N;;;;; +2E42;DOUBLE LOW-REVERSED-9 QUOTATION MARK;Ps;0;ON;;;;;N;;;;; 2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; 2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; 2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; @@ -13383,6 +13599,12 @@ A694;CYRILLIC CAPITAL LETTER HWE;Lu;0;L;;;;;N;;;;A695; A695;CYRILLIC SMALL LETTER HWE;Ll;0;L;;;;;N;;;A694;;A694 A696;CYRILLIC CAPITAL LETTER SHWE;Lu;0;L;;;;;N;;;;A697; A697;CYRILLIC SMALL LETTER SHWE;Ll;0;L;;;;;N;;;A696;;A696 +A698;CYRILLIC CAPITAL LETTER DOUBLE O;Lu;0;L;;;;;N;;;;A699; +A699;CYRILLIC SMALL LETTER DOUBLE O;Ll;0;L;;;;;N;;;A698;;A698 +A69A;CYRILLIC CAPITAL LETTER CROSSED O;Lu;0;L;;;;;N;;;;A69B; +A69B;CYRILLIC SMALL LETTER CROSSED O;Ll;0;L;;;;;N;;;A69A;;A69A +A69C;MODIFIER LETTER CYRILLIC HARD SIGN;Lm;0;L;<super> 044A;;;;N;;;;; +A69D;MODIFIER LETTER CYRILLIC SOFT SIGN;Lm;0;L;<super> 044C;;;;N;;;;; A69F;COMBINING CYRILLIC LETTER IOTIFIED E;Mn;230;NSM;;;;;N;;;;; A6A0;BAMUM LETTER A;Lo;0;L;;;;;N;;;;; A6A1;BAMUM LETTER KA;Lo;0;L;;;;;N;;;;; @@ -13619,6 +13841,18 @@ A790;LATIN CAPITAL LETTER N WITH DESCENDER;Lu;0;L;;;;;N;;;;A791; A791;LATIN SMALL LETTER N WITH DESCENDER;Ll;0;L;;;;;N;;;A790;;A790 A792;LATIN CAPITAL LETTER C WITH BAR;Lu;0;L;;;;;N;;;;A793; A793;LATIN SMALL LETTER C WITH BAR;Ll;0;L;;;;;N;;;A792;;A792 +A794;LATIN SMALL LETTER C WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +A795;LATIN SMALL LETTER H WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +A796;LATIN CAPITAL LETTER B WITH FLOURISH;Lu;0;L;;;;;N;;;;A797; +A797;LATIN SMALL LETTER B WITH FLOURISH;Ll;0;L;;;;;N;;;A796;;A796 +A798;LATIN CAPITAL LETTER F WITH STROKE;Lu;0;L;;;;;N;;;;A799; +A799;LATIN SMALL LETTER F WITH STROKE;Ll;0;L;;;;;N;;;A798;;A798 +A79A;LATIN CAPITAL LETTER VOLAPUK AE;Lu;0;L;;;;;N;;;;A79B; +A79B;LATIN SMALL LETTER VOLAPUK AE;Ll;0;L;;;;;N;;;A79A;;A79A +A79C;LATIN CAPITAL LETTER VOLAPUK OE;Lu;0;L;;;;;N;;;;A79D; +A79D;LATIN SMALL LETTER VOLAPUK OE;Ll;0;L;;;;;N;;;A79C;;A79C +A79E;LATIN CAPITAL LETTER VOLAPUK UE;Lu;0;L;;;;;N;;;;A79F; +A79F;LATIN SMALL LETTER VOLAPUK UE;Ll;0;L;;;;;N;;;A79E;;A79E A7A0;LATIN CAPITAL LETTER G WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A1; A7A1;LATIN SMALL LETTER G WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A0;;A7A0 A7A2;LATIN CAPITAL LETTER K WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A3; @@ -13630,6 +13864,12 @@ A7A7;LATIN SMALL LETTER R WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A6;;A7A6 A7A8;LATIN CAPITAL LETTER S WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A9; A7A9;LATIN SMALL LETTER S WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A8;;A7A8 A7AA;LATIN CAPITAL LETTER H WITH HOOK;Lu;0;L;;;;;N;;;;0266; +A7AB;LATIN CAPITAL LETTER REVERSED OPEN E;Lu;0;L;;;;;N;;;;025C; +A7AC;LATIN CAPITAL LETTER SCRIPT G;Lu;0;L;;;;;N;;;;0261; +A7AD;LATIN CAPITAL LETTER L WITH BELT;Lu;0;L;;;;;N;;;;026C; +A7B0;LATIN CAPITAL LETTER TURNED K;Lu;0;L;;;;;N;;;;029E; +A7B1;LATIN CAPITAL LETTER TURNED T;Lu;0;L;;;;;N;;;;0287; +A7F7;LATIN EPIGRAPHIC LETTER SIDEWAYS I;Lo;0;L;;;;;N;;;;; A7F8;MODIFIER LETTER CAPITAL H WITH STROKE;Lm;0;L;<super> 0126;;;;N;;;;; A7F9;MODIFIER LETTER SMALL LIGATURE OE;Lm;0;L;<super> 0153;;;;N;;;;; A7FA;LATIN LETTER SMALL CAPITAL TURNED M;Ll;0;L;;;;;N;;;;; @@ -14062,6 +14302,37 @@ A9D8;JAVANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; A9D9;JAVANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; A9DE;JAVANESE PADA TIRTA TUMETES;Po;0;L;;;;;N;;;;; A9DF;JAVANESE PADA ISEN-ISEN;Po;0;L;;;;;N;;;;; +A9E0;MYANMAR LETTER SHAN GHA;Lo;0;L;;;;;N;;;;; +A9E1;MYANMAR LETTER SHAN CHA;Lo;0;L;;;;;N;;;;; +A9E2;MYANMAR LETTER SHAN JHA;Lo;0;L;;;;;N;;;;; +A9E3;MYANMAR LETTER SHAN NNA;Lo;0;L;;;;;N;;;;; +A9E4;MYANMAR LETTER SHAN BHA;Lo;0;L;;;;;N;;;;; +A9E5;MYANMAR SIGN SHAN SAW;Mn;0;NSM;;;;;N;;;;; +A9E6;MYANMAR MODIFIER LETTER SHAN REDUPLICATION;Lm;0;L;;;;;N;;;;; +A9E7;MYANMAR LETTER TAI LAING NYA;Lo;0;L;;;;;N;;;;; +A9E8;MYANMAR LETTER TAI LAING FA;Lo;0;L;;;;;N;;;;; +A9E9;MYANMAR LETTER TAI LAING GA;Lo;0;L;;;;;N;;;;; +A9EA;MYANMAR LETTER TAI LAING GHA;Lo;0;L;;;;;N;;;;; +A9EB;MYANMAR LETTER TAI LAING JA;Lo;0;L;;;;;N;;;;; +A9EC;MYANMAR LETTER TAI LAING JHA;Lo;0;L;;;;;N;;;;; +A9ED;MYANMAR LETTER TAI LAING DDA;Lo;0;L;;;;;N;;;;; +A9EE;MYANMAR LETTER TAI LAING DDHA;Lo;0;L;;;;;N;;;;; +A9EF;MYANMAR LETTER TAI LAING NNA;Lo;0;L;;;;;N;;;;; +A9F0;MYANMAR TAI LAING DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +A9F1;MYANMAR TAI LAING DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +A9F2;MYANMAR TAI LAING DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +A9F3;MYANMAR TAI LAING DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +A9F4;MYANMAR TAI LAING DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +A9F5;MYANMAR TAI LAING DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +A9F6;MYANMAR TAI LAING DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +A9F7;MYANMAR TAI LAING DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +A9F8;MYANMAR TAI LAING DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +A9F9;MYANMAR TAI LAING DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +A9FA;MYANMAR LETTER TAI LAING LLA;Lo;0;L;;;;;N;;;;; +A9FB;MYANMAR LETTER TAI LAING DA;Lo;0;L;;;;;N;;;;; +A9FC;MYANMAR LETTER TAI LAING DHA;Lo;0;L;;;;;N;;;;; +A9FD;MYANMAR LETTER TAI LAING BA;Lo;0;L;;;;;N;;;;; +A9FE;MYANMAR LETTER TAI LAING BHA;Lo;0;L;;;;;N;;;;; AA00;CHAM LETTER A;Lo;0;L;;;;;N;;;;; AA01;CHAM LETTER I;Lo;0;L;;;;;N;;;;; AA02;CHAM LETTER U;Lo;0;L;;;;;N;;;;; @@ -14173,6 +14444,10 @@ AA78;MYANMAR SYMBOL AITON ONE;So;0;L;;;;;N;;;;; AA79;MYANMAR SYMBOL AITON TWO;So;0;L;;;;;N;;;;; AA7A;MYANMAR LETTER AITON RA;Lo;0;L;;;;;N;;;;; AA7B;MYANMAR SIGN PAO KAREN TONE;Mc;0;L;;;;;N;;;;; +AA7C;MYANMAR SIGN TAI LAING TONE-2;Mn;0;NSM;;;;;N;;;;; +AA7D;MYANMAR SIGN TAI LAING TONE-5;Mc;0;L;;;;;N;;;;; +AA7E;MYANMAR LETTER SHWE PALAUNG CHA;Lo;0;L;;;;;N;;;;; +AA7F;MYANMAR LETTER SHWE PALAUNG SHA;Lo;0;L;;;;;N;;;;; AA80;TAI VIET LETTER LOW KO;Lo;0;L;;;;;N;;;;; AA81;TAI VIET LETTER HIGH KO;Lo;0;L;;;;;N;;;;; AA82;TAI VIET LETTER LOW KHO;Lo;0;L;;;;;N;;;;; @@ -14300,6 +14575,56 @@ AB2B;ETHIOPIC SYLLABLE BBAA;Lo;0;L;;;;;N;;;;; AB2C;ETHIOPIC SYLLABLE BBEE;Lo;0;L;;;;;N;;;;; AB2D;ETHIOPIC SYLLABLE BBE;Lo;0;L;;;;;N;;;;; AB2E;ETHIOPIC SYLLABLE BBO;Lo;0;L;;;;;N;;;;; +AB30;LATIN SMALL LETTER BARRED ALPHA;Ll;0;L;;;;;N;;;;; +AB31;LATIN SMALL LETTER A REVERSED-SCHWA;Ll;0;L;;;;;N;;;;; +AB32;LATIN SMALL LETTER BLACKLETTER E;Ll;0;L;;;;;N;;;;; +AB33;LATIN SMALL LETTER BARRED E;Ll;0;L;;;;;N;;;;; +AB34;LATIN SMALL LETTER E WITH FLOURISH;Ll;0;L;;;;;N;;;;; +AB35;LATIN SMALL LETTER LENIS F;Ll;0;L;;;;;N;;;;; +AB36;LATIN SMALL LETTER SCRIPT G WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB37;LATIN SMALL LETTER L WITH INVERTED LAZY S;Ll;0;L;;;;;N;;;;; +AB38;LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +AB39;LATIN SMALL LETTER L WITH MIDDLE RING;Ll;0;L;;;;;N;;;;; +AB3A;LATIN SMALL LETTER M WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB3B;LATIN SMALL LETTER N WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB3C;LATIN SMALL LETTER ENG WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB3D;LATIN SMALL LETTER BLACKLETTER O;Ll;0;L;;;;;N;;;;; +AB3E;LATIN SMALL LETTER BLACKLETTER O WITH STROKE;Ll;0;L;;;;;N;;;;; +AB3F;LATIN SMALL LETTER OPEN O WITH STROKE;Ll;0;L;;;;;N;;;;; +AB40;LATIN SMALL LETTER INVERTED OE;Ll;0;L;;;;;N;;;;; +AB41;LATIN SMALL LETTER TURNED OE WITH STROKE;Ll;0;L;;;;;N;;;;; +AB42;LATIN SMALL LETTER TURNED OE WITH HORIZONTAL STROKE;Ll;0;L;;;;;N;;;;; +AB43;LATIN SMALL LETTER TURNED O OPEN-O;Ll;0;L;;;;;N;;;;; +AB44;LATIN SMALL LETTER TURNED O OPEN-O WITH STROKE;Ll;0;L;;;;;N;;;;; +AB45;LATIN SMALL LETTER STIRRUP R;Ll;0;L;;;;;N;;;;; +AB46;LATIN LETTER SMALL CAPITAL R WITH RIGHT LEG;Ll;0;L;;;;;N;;;;; +AB47;LATIN SMALL LETTER R WITHOUT HANDLE;Ll;0;L;;;;;N;;;;; +AB48;LATIN SMALL LETTER DOUBLE R;Ll;0;L;;;;;N;;;;; +AB49;LATIN SMALL LETTER R WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB4A;LATIN SMALL LETTER DOUBLE R WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;; +AB4B;LATIN SMALL LETTER SCRIPT R;Ll;0;L;;;;;N;;;;; +AB4C;LATIN SMALL LETTER SCRIPT R WITH RING;Ll;0;L;;;;;N;;;;; +AB4D;LATIN SMALL LETTER BASELINE ESH;Ll;0;L;;;;;N;;;;; +AB4E;LATIN SMALL LETTER U WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;; +AB4F;LATIN SMALL LETTER U BAR WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;; +AB50;LATIN SMALL LETTER UI;Ll;0;L;;;;;N;;;;; +AB51;LATIN SMALL LETTER TURNED UI;Ll;0;L;;;;;N;;;;; +AB52;LATIN SMALL LETTER U WITH LEFT HOOK;Ll;0;L;;;;;N;;;;; +AB53;LATIN SMALL LETTER CHI;Ll;0;L;;;;;N;;;;; +AB54;LATIN SMALL LETTER CHI WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;; +AB55;LATIN SMALL LETTER CHI WITH LOW LEFT SERIF;Ll;0;L;;;;;N;;;;; +AB56;LATIN SMALL LETTER X WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;; +AB57;LATIN SMALL LETTER X WITH LONG LEFT LEG;Ll;0;L;;;;;N;;;;; +AB58;LATIN SMALL LETTER X WITH LONG LEFT LEG AND LOW RIGHT RING;Ll;0;L;;;;;N;;;;; +AB59;LATIN SMALL LETTER X WITH LONG LEFT LEG WITH SERIF;Ll;0;L;;;;;N;;;;; +AB5A;LATIN SMALL LETTER Y WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;; +AB5B;MODIFIER BREVE WITH INVERTED BREVE;Sk;0;L;;;;;N;;;;; +AB5C;MODIFIER LETTER SMALL HENG;Lm;0;L;<super> A727;;;;N;;;;; +AB5D;MODIFIER LETTER SMALL L WITH INVERTED LAZY S;Lm;0;L;<super> AB37;;;;N;;;;; +AB5E;MODIFIER LETTER SMALL L WITH MIDDLE TILDE;Lm;0;L;<super> 026B;;;;N;;;;; +AB5F;MODIFIER LETTER SMALL U WITH LEFT HOOK;Lm;0;L;<super> AB52;;;;N;;;;; +AB64;LATIN SMALL LETTER INVERTED ALPHA;Ll;0;L;;;;;N;;;;; +AB65;GREEK LETTER SMALL CAPITAL OMEGA;Ll;0;L;;;;;N;;;;; ABC0;MEETEI MAYEK LETTER KOK;Lo;0;L;;;;;N;;;;; ABC1;MEETEI MAYEK LETTER SAM;Lo;0;L;;;;;N;;;;; ABC2;MEETEI MAYEK LETTER LAI;Lo;0;L;;;;;N;;;;; @@ -15445,8 +15770,8 @@ FD3A;ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0637 0645;;;;N;; FD3B;ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0638 0645;;;;N;;;;; FD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL;<final> 0627 064B;;;;N;;;;; FD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0627 064B;;;;N;;;;; -FD3E;ORNATE LEFT PARENTHESIS;Ps;0;ON;;;;;N;;;;; -FD3F;ORNATE RIGHT PARENTHESIS;Pe;0;ON;;;;;N;;;;; +FD3E;ORNATE LEFT PARENTHESIS;Pe;0;ON;;;;;N;;;;; +FD3F;ORNATE RIGHT PARENTHESIS;Ps;0;ON;;;;;N;;;;; FD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C 0645;;;;N;;;;; FD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL;<final> 062A 062D 062C;;;;N;;;;; FD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 062C;;;;N;;;;; @@ -15612,6 +15937,13 @@ FE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; FE24;COMBINING MACRON LEFT HALF;Mn;230;NSM;;;;;N;;;;; FE25;COMBINING MACRON RIGHT HALF;Mn;230;NSM;;;;;N;;;;; FE26;COMBINING CONJOINING MACRON;Mn;230;NSM;;;;;N;;;;; +FE27;COMBINING LIGATURE LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE28;COMBINING LIGATURE RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE29;COMBINING TILDE LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE2A;COMBINING TILDE RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE2B;COMBINING MACRON LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE2C;COMBINING MACRON RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;; +FE2D;COMBINING CONJOINING MACRON BELOW;Mn;220;NSM;;;;;N;;;;; FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON;<vertical> 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;; FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON;<vertical> 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;; FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON;<vertical> 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;; @@ -16384,6 +16716,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10188;GREEK GRAMMA SIGN;So;0;ON;;;;;N;;;;; 10189;GREEK TRYBLION BASE SIGN;So;0;ON;;;;;N;;;;; 1018A;GREEK ZERO SIGN;No;0;ON;;;;0;N;;;;; +1018B;GREEK ONE QUARTER SIGN;No;0;ON;;;;1/4;N;;;;; +1018C;GREEK SINUSOID SIGN;So;0;ON;;;;;N;;;;; 10190;ROMAN SEXTANS SIGN;So;0;ON;;;;;N;;;;; 10191;ROMAN UNCIA SIGN;So;0;ON;;;;;N;;;;; 10192;ROMAN SEMUNCIA SIGN;So;0;ON;;;;;N;;;;; @@ -16396,6 +16730,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10199;ROMAN DUPONDIUS SIGN;So;0;ON;;;;;N;;;;; 1019A;ROMAN AS SIGN;So;0;ON;;;;;N;;;;; 1019B;ROMAN CENTURIAL SIGN;So;0;ON;;;;;N;;;;; +101A0;GREEK SYMBOL TAU RHO;So;0;ON;;;;;N;;;;; 101D0;PHAISTOS DISC SIGN PEDESTRIAN;So;0;L;;;;;N;;;;; 101D1;PHAISTOS DISC SIGN PLUMED HEAD;So;0;L;;;;;N;;;;; 101D2;PHAISTOS DISC SIGN TATTOOED HEAD;So;0;L;;;;;N;;;;; @@ -16520,6 +16855,34 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 102CE;CARIAN LETTER LD2;Lo;0;L;;;;;N;;;;; 102CF;CARIAN LETTER E2;Lo;0;L;;;;;N;;;;; 102D0;CARIAN LETTER UUU3;Lo;0;L;;;;;N;;;;; +102E0;COPTIC EPACT THOUSANDS MARK;Mn;220;NSM;;;;;N;;;;; +102E1;COPTIC EPACT DIGIT ONE;No;0;EN;;;;1;N;;;;; +102E2;COPTIC EPACT DIGIT TWO;No;0;EN;;;;2;N;;;;; +102E3;COPTIC EPACT DIGIT THREE;No;0;EN;;;;3;N;;;;; +102E4;COPTIC EPACT DIGIT FOUR;No;0;EN;;;;4;N;;;;; +102E5;COPTIC EPACT DIGIT FIVE;No;0;EN;;;;5;N;;;;; +102E6;COPTIC EPACT DIGIT SIX;No;0;EN;;;;6;N;;;;; +102E7;COPTIC EPACT DIGIT SEVEN;No;0;EN;;;;7;N;;;;; +102E8;COPTIC EPACT DIGIT EIGHT;No;0;EN;;;;8;N;;;;; +102E9;COPTIC EPACT DIGIT NINE;No;0;EN;;;;9;N;;;;; +102EA;COPTIC EPACT NUMBER TEN;No;0;EN;;;;10;N;;;;; +102EB;COPTIC EPACT NUMBER TWENTY;No;0;EN;;;;20;N;;;;; +102EC;COPTIC EPACT NUMBER THIRTY;No;0;EN;;;;30;N;;;;; +102ED;COPTIC EPACT NUMBER FORTY;No;0;EN;;;;40;N;;;;; +102EE;COPTIC EPACT NUMBER FIFTY;No;0;EN;;;;50;N;;;;; +102EF;COPTIC EPACT NUMBER SIXTY;No;0;EN;;;;60;N;;;;; +102F0;COPTIC EPACT NUMBER SEVENTY;No;0;EN;;;;70;N;;;;; +102F1;COPTIC EPACT NUMBER EIGHTY;No;0;EN;;;;80;N;;;;; +102F2;COPTIC EPACT NUMBER NINETY;No;0;EN;;;;90;N;;;;; +102F3;COPTIC EPACT NUMBER ONE HUNDRED;No;0;EN;;;;100;N;;;;; +102F4;COPTIC EPACT NUMBER TWO HUNDRED;No;0;EN;;;;200;N;;;;; +102F5;COPTIC EPACT NUMBER THREE HUNDRED;No;0;EN;;;;300;N;;;;; +102F6;COPTIC EPACT NUMBER FOUR HUNDRED;No;0;EN;;;;400;N;;;;; +102F7;COPTIC EPACT NUMBER FIVE HUNDRED;No;0;EN;;;;500;N;;;;; +102F8;COPTIC EPACT NUMBER SIX HUNDRED;No;0;EN;;;;600;N;;;;; +102F9;COPTIC EPACT NUMBER SEVEN HUNDRED;No;0;EN;;;;700;N;;;;; +102FA;COPTIC EPACT NUMBER EIGHT HUNDRED;No;0;EN;;;;800;N;;;;; +102FB;COPTIC EPACT NUMBER NINE HUNDRED;No;0;EN;;;;900;N;;;;; 10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;; 10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;; 10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;; @@ -16551,6 +16914,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1031C;OLD ITALIC LETTER CHE;Lo;0;L;;;;;N;;;;; 1031D;OLD ITALIC LETTER II;Lo;0;L;;;;;N;;;;; 1031E;OLD ITALIC LETTER UU;Lo;0;L;;;;;N;;;;; +1031F;OLD ITALIC LETTER ESS;Lo;0;L;;;;;N;;;;; 10320;OLD ITALIC NUMERAL ONE;No;0;L;;;;1;N;;;;; 10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;; 10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;; @@ -16582,6 +16946,49 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;; 10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;; 1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;900;N;;;;; +10350;OLD PERMIC LETTER AN;Lo;0;L;;;;;N;;;;; +10351;OLD PERMIC LETTER BUR;Lo;0;L;;;;;N;;;;; +10352;OLD PERMIC LETTER GAI;Lo;0;L;;;;;N;;;;; +10353;OLD PERMIC LETTER DOI;Lo;0;L;;;;;N;;;;; +10354;OLD PERMIC LETTER E;Lo;0;L;;;;;N;;;;; +10355;OLD PERMIC LETTER ZHOI;Lo;0;L;;;;;N;;;;; +10356;OLD PERMIC LETTER DZHOI;Lo;0;L;;;;;N;;;;; +10357;OLD PERMIC LETTER ZATA;Lo;0;L;;;;;N;;;;; +10358;OLD PERMIC LETTER DZITA;Lo;0;L;;;;;N;;;;; +10359;OLD PERMIC LETTER I;Lo;0;L;;;;;N;;;;; +1035A;OLD PERMIC LETTER KOKE;Lo;0;L;;;;;N;;;;; +1035B;OLD PERMIC LETTER LEI;Lo;0;L;;;;;N;;;;; +1035C;OLD PERMIC LETTER MENOE;Lo;0;L;;;;;N;;;;; +1035D;OLD PERMIC LETTER NENOE;Lo;0;L;;;;;N;;;;; +1035E;OLD PERMIC LETTER VOOI;Lo;0;L;;;;;N;;;;; +1035F;OLD PERMIC LETTER PEEI;Lo;0;L;;;;;N;;;;; +10360;OLD PERMIC LETTER REI;Lo;0;L;;;;;N;;;;; +10361;OLD PERMIC LETTER SII;Lo;0;L;;;;;N;;;;; +10362;OLD PERMIC LETTER TAI;Lo;0;L;;;;;N;;;;; +10363;OLD PERMIC LETTER U;Lo;0;L;;;;;N;;;;; +10364;OLD PERMIC LETTER CHERY;Lo;0;L;;;;;N;;;;; +10365;OLD PERMIC LETTER SHOOI;Lo;0;L;;;;;N;;;;; +10366;OLD PERMIC LETTER SHCHOOI;Lo;0;L;;;;;N;;;;; +10367;OLD PERMIC LETTER YRY;Lo;0;L;;;;;N;;;;; +10368;OLD PERMIC LETTER YERU;Lo;0;L;;;;;N;;;;; +10369;OLD PERMIC LETTER O;Lo;0;L;;;;;N;;;;; +1036A;OLD PERMIC LETTER OO;Lo;0;L;;;;;N;;;;; +1036B;OLD PERMIC LETTER EF;Lo;0;L;;;;;N;;;;; +1036C;OLD PERMIC LETTER HA;Lo;0;L;;;;;N;;;;; +1036D;OLD PERMIC LETTER TSIU;Lo;0;L;;;;;N;;;;; +1036E;OLD PERMIC LETTER VER;Lo;0;L;;;;;N;;;;; +1036F;OLD PERMIC LETTER YER;Lo;0;L;;;;;N;;;;; +10370;OLD PERMIC LETTER YERI;Lo;0;L;;;;;N;;;;; +10371;OLD PERMIC LETTER YAT;Lo;0;L;;;;;N;;;;; +10372;OLD PERMIC LETTER IE;Lo;0;L;;;;;N;;;;; +10373;OLD PERMIC LETTER YU;Lo;0;L;;;;;N;;;;; +10374;OLD PERMIC LETTER YA;Lo;0;L;;;;;N;;;;; +10375;OLD PERMIC LETTER IA;Lo;0;L;;;;;N;;;;; +10376;COMBINING OLD PERMIC LETTER AN;Mn;230;NSM;;;;;N;;;;; +10377;COMBINING OLD PERMIC LETTER DOI;Mn;230;NSM;;;;;N;;;;; +10378;COMBINING OLD PERMIC LETTER ZATA;Mn;230;NSM;;;;;N;;;;; +10379;COMBINING OLD PERMIC LETTER NENOE;Mn;230;NSM;;;;;N;;;;; +1037A;COMBINING OLD PERMIC LETTER SII;Mn;230;NSM;;;;;N;;;;; 10380;UGARITIC LETTER ALPA;Lo;0;L;;;;;N;;;;; 10381;UGARITIC LETTER BETA;Lo;0;L;;;;;N;;;;; 10382;UGARITIC LETTER GAMLA;Lo;0;L;;;;;N;;;;; @@ -16831,6 +17238,440 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 104A7;OSMANYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 104A8;OSMANYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 104A9;OSMANYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +10500;ELBASAN LETTER A;Lo;0;L;;;;;N;;;;; +10501;ELBASAN LETTER BE;Lo;0;L;;;;;N;;;;; +10502;ELBASAN LETTER CE;Lo;0;L;;;;;N;;;;; +10503;ELBASAN LETTER CHE;Lo;0;L;;;;;N;;;;; +10504;ELBASAN LETTER DE;Lo;0;L;;;;;N;;;;; +10505;ELBASAN LETTER NDE;Lo;0;L;;;;;N;;;;; +10506;ELBASAN LETTER DHE;Lo;0;L;;;;;N;;;;; +10507;ELBASAN LETTER EI;Lo;0;L;;;;;N;;;;; +10508;ELBASAN LETTER E;Lo;0;L;;;;;N;;;;; +10509;ELBASAN LETTER FE;Lo;0;L;;;;;N;;;;; +1050A;ELBASAN LETTER GE;Lo;0;L;;;;;N;;;;; +1050B;ELBASAN LETTER GJE;Lo;0;L;;;;;N;;;;; +1050C;ELBASAN LETTER HE;Lo;0;L;;;;;N;;;;; +1050D;ELBASAN LETTER I;Lo;0;L;;;;;N;;;;; +1050E;ELBASAN LETTER JE;Lo;0;L;;;;;N;;;;; +1050F;ELBASAN LETTER KE;Lo;0;L;;;;;N;;;;; +10510;ELBASAN LETTER LE;Lo;0;L;;;;;N;;;;; +10511;ELBASAN LETTER LLE;Lo;0;L;;;;;N;;;;; +10512;ELBASAN LETTER ME;Lo;0;L;;;;;N;;;;; +10513;ELBASAN LETTER NE;Lo;0;L;;;;;N;;;;; +10514;ELBASAN LETTER NA;Lo;0;L;;;;;N;;;;; +10515;ELBASAN LETTER NJE;Lo;0;L;;;;;N;;;;; +10516;ELBASAN LETTER O;Lo;0;L;;;;;N;;;;; +10517;ELBASAN LETTER PE;Lo;0;L;;;;;N;;;;; +10518;ELBASAN LETTER QE;Lo;0;L;;;;;N;;;;; +10519;ELBASAN LETTER RE;Lo;0;L;;;;;N;;;;; +1051A;ELBASAN LETTER RRE;Lo;0;L;;;;;N;;;;; +1051B;ELBASAN LETTER SE;Lo;0;L;;;;;N;;;;; +1051C;ELBASAN LETTER SHE;Lo;0;L;;;;;N;;;;; +1051D;ELBASAN LETTER TE;Lo;0;L;;;;;N;;;;; +1051E;ELBASAN LETTER THE;Lo;0;L;;;;;N;;;;; +1051F;ELBASAN LETTER U;Lo;0;L;;;;;N;;;;; +10520;ELBASAN LETTER VE;Lo;0;L;;;;;N;;;;; +10521;ELBASAN LETTER XE;Lo;0;L;;;;;N;;;;; +10522;ELBASAN LETTER Y;Lo;0;L;;;;;N;;;;; +10523;ELBASAN LETTER ZE;Lo;0;L;;;;;N;;;;; +10524;ELBASAN LETTER ZHE;Lo;0;L;;;;;N;;;;; +10525;ELBASAN LETTER GHE;Lo;0;L;;;;;N;;;;; +10526;ELBASAN LETTER GHAMMA;Lo;0;L;;;;;N;;;;; +10527;ELBASAN LETTER KHE;Lo;0;L;;;;;N;;;;; +10530;CAUCASIAN ALBANIAN LETTER ALT;Lo;0;L;;;;;N;;;;; +10531;CAUCASIAN ALBANIAN LETTER BET;Lo;0;L;;;;;N;;;;; +10532;CAUCASIAN ALBANIAN LETTER GIM;Lo;0;L;;;;;N;;;;; +10533;CAUCASIAN ALBANIAN LETTER DAT;Lo;0;L;;;;;N;;;;; +10534;CAUCASIAN ALBANIAN LETTER EB;Lo;0;L;;;;;N;;;;; +10535;CAUCASIAN ALBANIAN LETTER ZARL;Lo;0;L;;;;;N;;;;; +10536;CAUCASIAN ALBANIAN LETTER EYN;Lo;0;L;;;;;N;;;;; +10537;CAUCASIAN ALBANIAN LETTER ZHIL;Lo;0;L;;;;;N;;;;; +10538;CAUCASIAN ALBANIAN LETTER TAS;Lo;0;L;;;;;N;;;;; +10539;CAUCASIAN ALBANIAN LETTER CHA;Lo;0;L;;;;;N;;;;; +1053A;CAUCASIAN ALBANIAN LETTER YOWD;Lo;0;L;;;;;N;;;;; +1053B;CAUCASIAN ALBANIAN LETTER ZHA;Lo;0;L;;;;;N;;;;; +1053C;CAUCASIAN ALBANIAN LETTER IRB;Lo;0;L;;;;;N;;;;; +1053D;CAUCASIAN ALBANIAN LETTER SHA;Lo;0;L;;;;;N;;;;; +1053E;CAUCASIAN ALBANIAN LETTER LAN;Lo;0;L;;;;;N;;;;; +1053F;CAUCASIAN ALBANIAN LETTER INYA;Lo;0;L;;;;;N;;;;; +10540;CAUCASIAN ALBANIAN LETTER XEYN;Lo;0;L;;;;;N;;;;; +10541;CAUCASIAN ALBANIAN LETTER DYAN;Lo;0;L;;;;;N;;;;; +10542;CAUCASIAN ALBANIAN LETTER CAR;Lo;0;L;;;;;N;;;;; +10543;CAUCASIAN ALBANIAN LETTER JHOX;Lo;0;L;;;;;N;;;;; +10544;CAUCASIAN ALBANIAN LETTER KAR;Lo;0;L;;;;;N;;;;; +10545;CAUCASIAN ALBANIAN LETTER LYIT;Lo;0;L;;;;;N;;;;; +10546;CAUCASIAN ALBANIAN LETTER HEYT;Lo;0;L;;;;;N;;;;; +10547;CAUCASIAN ALBANIAN LETTER QAY;Lo;0;L;;;;;N;;;;; +10548;CAUCASIAN ALBANIAN LETTER AOR;Lo;0;L;;;;;N;;;;; +10549;CAUCASIAN ALBANIAN LETTER CHOY;Lo;0;L;;;;;N;;;;; +1054A;CAUCASIAN ALBANIAN LETTER CHI;Lo;0;L;;;;;N;;;;; +1054B;CAUCASIAN ALBANIAN LETTER CYAY;Lo;0;L;;;;;N;;;;; +1054C;CAUCASIAN ALBANIAN LETTER MAQ;Lo;0;L;;;;;N;;;;; +1054D;CAUCASIAN ALBANIAN LETTER QAR;Lo;0;L;;;;;N;;;;; +1054E;CAUCASIAN ALBANIAN LETTER NOWC;Lo;0;L;;;;;N;;;;; +1054F;CAUCASIAN ALBANIAN LETTER DZYAY;Lo;0;L;;;;;N;;;;; +10550;CAUCASIAN ALBANIAN LETTER SHAK;Lo;0;L;;;;;N;;;;; +10551;CAUCASIAN ALBANIAN LETTER JAYN;Lo;0;L;;;;;N;;;;; +10552;CAUCASIAN ALBANIAN LETTER ON;Lo;0;L;;;;;N;;;;; +10553;CAUCASIAN ALBANIAN LETTER TYAY;Lo;0;L;;;;;N;;;;; +10554;CAUCASIAN ALBANIAN LETTER FAM;Lo;0;L;;;;;N;;;;; +10555;CAUCASIAN ALBANIAN LETTER DZAY;Lo;0;L;;;;;N;;;;; +10556;CAUCASIAN ALBANIAN LETTER CHAT;Lo;0;L;;;;;N;;;;; +10557;CAUCASIAN ALBANIAN LETTER PEN;Lo;0;L;;;;;N;;;;; +10558;CAUCASIAN ALBANIAN LETTER GHEYS;Lo;0;L;;;;;N;;;;; +10559;CAUCASIAN ALBANIAN LETTER RAT;Lo;0;L;;;;;N;;;;; +1055A;CAUCASIAN ALBANIAN LETTER SEYK;Lo;0;L;;;;;N;;;;; +1055B;CAUCASIAN ALBANIAN LETTER VEYZ;Lo;0;L;;;;;N;;;;; +1055C;CAUCASIAN ALBANIAN LETTER TIWR;Lo;0;L;;;;;N;;;;; +1055D;CAUCASIAN ALBANIAN LETTER SHOY;Lo;0;L;;;;;N;;;;; +1055E;CAUCASIAN ALBANIAN LETTER IWN;Lo;0;L;;;;;N;;;;; +1055F;CAUCASIAN ALBANIAN LETTER CYAW;Lo;0;L;;;;;N;;;;; +10560;CAUCASIAN ALBANIAN LETTER CAYN;Lo;0;L;;;;;N;;;;; +10561;CAUCASIAN ALBANIAN LETTER YAYD;Lo;0;L;;;;;N;;;;; +10562;CAUCASIAN ALBANIAN LETTER PIWR;Lo;0;L;;;;;N;;;;; +10563;CAUCASIAN ALBANIAN LETTER KIW;Lo;0;L;;;;;N;;;;; +1056F;CAUCASIAN ALBANIAN CITATION MARK;Po;0;L;;;;;N;;;;; +10600;LINEAR A SIGN AB001;Lo;0;L;;;;;N;;;;; +10601;LINEAR A SIGN AB002;Lo;0;L;;;;;N;;;;; +10602;LINEAR A SIGN AB003;Lo;0;L;;;;;N;;;;; +10603;LINEAR A SIGN AB004;Lo;0;L;;;;;N;;;;; +10604;LINEAR A SIGN AB005;Lo;0;L;;;;;N;;;;; +10605;LINEAR A SIGN AB006;Lo;0;L;;;;;N;;;;; +10606;LINEAR A SIGN AB007;Lo;0;L;;;;;N;;;;; +10607;LINEAR A SIGN AB008;Lo;0;L;;;;;N;;;;; +10608;LINEAR A SIGN AB009;Lo;0;L;;;;;N;;;;; +10609;LINEAR A SIGN AB010;Lo;0;L;;;;;N;;;;; +1060A;LINEAR A SIGN AB011;Lo;0;L;;;;;N;;;;; +1060B;LINEAR A SIGN AB013;Lo;0;L;;;;;N;;;;; +1060C;LINEAR A SIGN AB016;Lo;0;L;;;;;N;;;;; +1060D;LINEAR A SIGN AB017;Lo;0;L;;;;;N;;;;; +1060E;LINEAR A SIGN AB020;Lo;0;L;;;;;N;;;;; +1060F;LINEAR A SIGN AB021;Lo;0;L;;;;;N;;;;; +10610;LINEAR A SIGN AB021F;Lo;0;L;;;;;N;;;;; +10611;LINEAR A SIGN AB021M;Lo;0;L;;;;;N;;;;; +10612;LINEAR A SIGN AB022;Lo;0;L;;;;;N;;;;; +10613;LINEAR A SIGN AB022F;Lo;0;L;;;;;N;;;;; +10614;LINEAR A SIGN AB022M;Lo;0;L;;;;;N;;;;; +10615;LINEAR A SIGN AB023;Lo;0;L;;;;;N;;;;; +10616;LINEAR A SIGN AB023M;Lo;0;L;;;;;N;;;;; +10617;LINEAR A SIGN AB024;Lo;0;L;;;;;N;;;;; +10618;LINEAR A SIGN AB026;Lo;0;L;;;;;N;;;;; +10619;LINEAR A SIGN AB027;Lo;0;L;;;;;N;;;;; +1061A;LINEAR A SIGN AB028;Lo;0;L;;;;;N;;;;; +1061B;LINEAR A SIGN A028B;Lo;0;L;;;;;N;;;;; +1061C;LINEAR A SIGN AB029;Lo;0;L;;;;;N;;;;; +1061D;LINEAR A SIGN AB030;Lo;0;L;;;;;N;;;;; +1061E;LINEAR A SIGN AB031;Lo;0;L;;;;;N;;;;; +1061F;LINEAR A SIGN AB034;Lo;0;L;;;;;N;;;;; +10620;LINEAR A SIGN AB037;Lo;0;L;;;;;N;;;;; +10621;LINEAR A SIGN AB038;Lo;0;L;;;;;N;;;;; +10622;LINEAR A SIGN AB039;Lo;0;L;;;;;N;;;;; +10623;LINEAR A SIGN AB040;Lo;0;L;;;;;N;;;;; +10624;LINEAR A SIGN AB041;Lo;0;L;;;;;N;;;;; +10625;LINEAR A SIGN AB044;Lo;0;L;;;;;N;;;;; +10626;LINEAR A SIGN AB045;Lo;0;L;;;;;N;;;;; +10627;LINEAR A SIGN AB046;Lo;0;L;;;;;N;;;;; +10628;LINEAR A SIGN AB047;Lo;0;L;;;;;N;;;;; +10629;LINEAR A SIGN AB048;Lo;0;L;;;;;N;;;;; +1062A;LINEAR A SIGN AB049;Lo;0;L;;;;;N;;;;; +1062B;LINEAR A SIGN AB050;Lo;0;L;;;;;N;;;;; +1062C;LINEAR A SIGN AB051;Lo;0;L;;;;;N;;;;; +1062D;LINEAR A SIGN AB053;Lo;0;L;;;;;N;;;;; +1062E;LINEAR A SIGN AB054;Lo;0;L;;;;;N;;;;; +1062F;LINEAR A SIGN AB055;Lo;0;L;;;;;N;;;;; +10630;LINEAR A SIGN AB056;Lo;0;L;;;;;N;;;;; +10631;LINEAR A SIGN AB057;Lo;0;L;;;;;N;;;;; +10632;LINEAR A SIGN AB058;Lo;0;L;;;;;N;;;;; +10633;LINEAR A SIGN AB059;Lo;0;L;;;;;N;;;;; +10634;LINEAR A SIGN AB060;Lo;0;L;;;;;N;;;;; +10635;LINEAR A SIGN AB061;Lo;0;L;;;;;N;;;;; +10636;LINEAR A SIGN AB065;Lo;0;L;;;;;N;;;;; +10637;LINEAR A SIGN AB066;Lo;0;L;;;;;N;;;;; +10638;LINEAR A SIGN AB067;Lo;0;L;;;;;N;;;;; +10639;LINEAR A SIGN AB069;Lo;0;L;;;;;N;;;;; +1063A;LINEAR A SIGN AB070;Lo;0;L;;;;;N;;;;; +1063B;LINEAR A SIGN AB073;Lo;0;L;;;;;N;;;;; +1063C;LINEAR A SIGN AB074;Lo;0;L;;;;;N;;;;; +1063D;LINEAR A SIGN AB076;Lo;0;L;;;;;N;;;;; +1063E;LINEAR A SIGN AB077;Lo;0;L;;;;;N;;;;; +1063F;LINEAR A SIGN AB078;Lo;0;L;;;;;N;;;;; +10640;LINEAR A SIGN AB079;Lo;0;L;;;;;N;;;;; +10641;LINEAR A SIGN AB080;Lo;0;L;;;;;N;;;;; +10642;LINEAR A SIGN AB081;Lo;0;L;;;;;N;;;;; +10643;LINEAR A SIGN AB082;Lo;0;L;;;;;N;;;;; +10644;LINEAR A SIGN AB085;Lo;0;L;;;;;N;;;;; +10645;LINEAR A SIGN AB086;Lo;0;L;;;;;N;;;;; +10646;LINEAR A SIGN AB087;Lo;0;L;;;;;N;;;;; +10647;LINEAR A SIGN A100-102;Lo;0;L;;;;;N;;;;; +10648;LINEAR A SIGN AB118;Lo;0;L;;;;;N;;;;; +10649;LINEAR A SIGN AB120;Lo;0;L;;;;;N;;;;; +1064A;LINEAR A SIGN A120B;Lo;0;L;;;;;N;;;;; +1064B;LINEAR A SIGN AB122;Lo;0;L;;;;;N;;;;; +1064C;LINEAR A SIGN AB123;Lo;0;L;;;;;N;;;;; +1064D;LINEAR A SIGN AB131A;Lo;0;L;;;;;N;;;;; +1064E;LINEAR A SIGN AB131B;Lo;0;L;;;;;N;;;;; +1064F;LINEAR A SIGN A131C;Lo;0;L;;;;;N;;;;; +10650;LINEAR A SIGN AB164;Lo;0;L;;;;;N;;;;; +10651;LINEAR A SIGN AB171;Lo;0;L;;;;;N;;;;; +10652;LINEAR A SIGN AB180;Lo;0;L;;;;;N;;;;; +10653;LINEAR A SIGN AB188;Lo;0;L;;;;;N;;;;; +10654;LINEAR A SIGN AB191;Lo;0;L;;;;;N;;;;; +10655;LINEAR A SIGN A301;Lo;0;L;;;;;N;;;;; +10656;LINEAR A SIGN A302;Lo;0;L;;;;;N;;;;; +10657;LINEAR A SIGN A303;Lo;0;L;;;;;N;;;;; +10658;LINEAR A SIGN A304;Lo;0;L;;;;;N;;;;; +10659;LINEAR A SIGN A305;Lo;0;L;;;;;N;;;;; +1065A;LINEAR A SIGN A306;Lo;0;L;;;;;N;;;;; +1065B;LINEAR A SIGN A307;Lo;0;L;;;;;N;;;;; +1065C;LINEAR A SIGN A308;Lo;0;L;;;;;N;;;;; +1065D;LINEAR A SIGN A309A;Lo;0;L;;;;;N;;;;; +1065E;LINEAR A SIGN A309B;Lo;0;L;;;;;N;;;;; +1065F;LINEAR A SIGN A309C;Lo;0;L;;;;;N;;;;; +10660;LINEAR A SIGN A310;Lo;0;L;;;;;N;;;;; +10661;LINEAR A SIGN A311;Lo;0;L;;;;;N;;;;; +10662;LINEAR A SIGN A312;Lo;0;L;;;;;N;;;;; +10663;LINEAR A SIGN A313A;Lo;0;L;;;;;N;;;;; +10664;LINEAR A SIGN A313B;Lo;0;L;;;;;N;;;;; +10665;LINEAR A SIGN A313C;Lo;0;L;;;;;N;;;;; +10666;LINEAR A SIGN A314;Lo;0;L;;;;;N;;;;; +10667;LINEAR A SIGN A315;Lo;0;L;;;;;N;;;;; +10668;LINEAR A SIGN A316;Lo;0;L;;;;;N;;;;; +10669;LINEAR A SIGN A317;Lo;0;L;;;;;N;;;;; +1066A;LINEAR A SIGN A318;Lo;0;L;;;;;N;;;;; +1066B;LINEAR A SIGN A319;Lo;0;L;;;;;N;;;;; +1066C;LINEAR A SIGN A320;Lo;0;L;;;;;N;;;;; +1066D;LINEAR A SIGN A321;Lo;0;L;;;;;N;;;;; +1066E;LINEAR A SIGN A322;Lo;0;L;;;;;N;;;;; +1066F;LINEAR A SIGN A323;Lo;0;L;;;;;N;;;;; +10670;LINEAR A SIGN A324;Lo;0;L;;;;;N;;;;; +10671;LINEAR A SIGN A325;Lo;0;L;;;;;N;;;;; +10672;LINEAR A SIGN A326;Lo;0;L;;;;;N;;;;; +10673;LINEAR A SIGN A327;Lo;0;L;;;;;N;;;;; +10674;LINEAR A SIGN A328;Lo;0;L;;;;;N;;;;; +10675;LINEAR A SIGN A329;Lo;0;L;;;;;N;;;;; +10676;LINEAR A SIGN A330;Lo;0;L;;;;;N;;;;; +10677;LINEAR A SIGN A331;Lo;0;L;;;;;N;;;;; +10678;LINEAR A SIGN A332;Lo;0;L;;;;;N;;;;; +10679;LINEAR A SIGN A333;Lo;0;L;;;;;N;;;;; +1067A;LINEAR A SIGN A334;Lo;0;L;;;;;N;;;;; +1067B;LINEAR A SIGN A335;Lo;0;L;;;;;N;;;;; +1067C;LINEAR A SIGN A336;Lo;0;L;;;;;N;;;;; +1067D;LINEAR A SIGN A337;Lo;0;L;;;;;N;;;;; +1067E;LINEAR A SIGN A338;Lo;0;L;;;;;N;;;;; +1067F;LINEAR A SIGN A339;Lo;0;L;;;;;N;;;;; +10680;LINEAR A SIGN A340;Lo;0;L;;;;;N;;;;; +10681;LINEAR A SIGN A341;Lo;0;L;;;;;N;;;;; +10682;LINEAR A SIGN A342;Lo;0;L;;;;;N;;;;; +10683;LINEAR A SIGN A343;Lo;0;L;;;;;N;;;;; +10684;LINEAR A SIGN A344;Lo;0;L;;;;;N;;;;; +10685;LINEAR A SIGN A345;Lo;0;L;;;;;N;;;;; +10686;LINEAR A SIGN A346;Lo;0;L;;;;;N;;;;; +10687;LINEAR A SIGN A347;Lo;0;L;;;;;N;;;;; +10688;LINEAR A SIGN A348;Lo;0;L;;;;;N;;;;; +10689;LINEAR A SIGN A349;Lo;0;L;;;;;N;;;;; +1068A;LINEAR A SIGN A350;Lo;0;L;;;;;N;;;;; +1068B;LINEAR A SIGN A351;Lo;0;L;;;;;N;;;;; +1068C;LINEAR A SIGN A352;Lo;0;L;;;;;N;;;;; +1068D;LINEAR A SIGN A353;Lo;0;L;;;;;N;;;;; +1068E;LINEAR A SIGN A354;Lo;0;L;;;;;N;;;;; +1068F;LINEAR A SIGN A355;Lo;0;L;;;;;N;;;;; +10690;LINEAR A SIGN A356;Lo;0;L;;;;;N;;;;; +10691;LINEAR A SIGN A357;Lo;0;L;;;;;N;;;;; +10692;LINEAR A SIGN A358;Lo;0;L;;;;;N;;;;; +10693;LINEAR A SIGN A359;Lo;0;L;;;;;N;;;;; +10694;LINEAR A SIGN A360;Lo;0;L;;;;;N;;;;; +10695;LINEAR A SIGN A361;Lo;0;L;;;;;N;;;;; +10696;LINEAR A SIGN A362;Lo;0;L;;;;;N;;;;; +10697;LINEAR A SIGN A363;Lo;0;L;;;;;N;;;;; +10698;LINEAR A SIGN A364;Lo;0;L;;;;;N;;;;; +10699;LINEAR A SIGN A365;Lo;0;L;;;;;N;;;;; +1069A;LINEAR A SIGN A366;Lo;0;L;;;;;N;;;;; +1069B;LINEAR A SIGN A367;Lo;0;L;;;;;N;;;;; +1069C;LINEAR A SIGN A368;Lo;0;L;;;;;N;;;;; +1069D;LINEAR A SIGN A369;Lo;0;L;;;;;N;;;;; +1069E;LINEAR A SIGN A370;Lo;0;L;;;;;N;;;;; +1069F;LINEAR A SIGN A371;Lo;0;L;;;;;N;;;;; +106A0;LINEAR A SIGN A400-VAS;Lo;0;L;;;;;N;;;;; +106A1;LINEAR A SIGN A401-VAS;Lo;0;L;;;;;N;;;;; +106A2;LINEAR A SIGN A402-VAS;Lo;0;L;;;;;N;;;;; +106A3;LINEAR A SIGN A403-VAS;Lo;0;L;;;;;N;;;;; +106A4;LINEAR A SIGN A404-VAS;Lo;0;L;;;;;N;;;;; +106A5;LINEAR A SIGN A405-VAS;Lo;0;L;;;;;N;;;;; +106A6;LINEAR A SIGN A406-VAS;Lo;0;L;;;;;N;;;;; +106A7;LINEAR A SIGN A407-VAS;Lo;0;L;;;;;N;;;;; +106A8;LINEAR A SIGN A408-VAS;Lo;0;L;;;;;N;;;;; +106A9;LINEAR A SIGN A409-VAS;Lo;0;L;;;;;N;;;;; +106AA;LINEAR A SIGN A410-VAS;Lo;0;L;;;;;N;;;;; +106AB;LINEAR A SIGN A411-VAS;Lo;0;L;;;;;N;;;;; +106AC;LINEAR A SIGN A412-VAS;Lo;0;L;;;;;N;;;;; +106AD;LINEAR A SIGN A413-VAS;Lo;0;L;;;;;N;;;;; +106AE;LINEAR A SIGN A414-VAS;Lo;0;L;;;;;N;;;;; +106AF;LINEAR A SIGN A415-VAS;Lo;0;L;;;;;N;;;;; +106B0;LINEAR A SIGN A416-VAS;Lo;0;L;;;;;N;;;;; +106B1;LINEAR A SIGN A417-VAS;Lo;0;L;;;;;N;;;;; +106B2;LINEAR A SIGN A418-VAS;Lo;0;L;;;;;N;;;;; +106B3;LINEAR A SIGN A501;Lo;0;L;;;;;N;;;;; +106B4;LINEAR A SIGN A502;Lo;0;L;;;;;N;;;;; +106B5;LINEAR A SIGN A503;Lo;0;L;;;;;N;;;;; +106B6;LINEAR A SIGN A504;Lo;0;L;;;;;N;;;;; +106B7;LINEAR A SIGN A505;Lo;0;L;;;;;N;;;;; +106B8;LINEAR A SIGN A506;Lo;0;L;;;;;N;;;;; +106B9;LINEAR A SIGN A508;Lo;0;L;;;;;N;;;;; +106BA;LINEAR A SIGN A509;Lo;0;L;;;;;N;;;;; +106BB;LINEAR A SIGN A510;Lo;0;L;;;;;N;;;;; +106BC;LINEAR A SIGN A511;Lo;0;L;;;;;N;;;;; +106BD;LINEAR A SIGN A512;Lo;0;L;;;;;N;;;;; +106BE;LINEAR A SIGN A513;Lo;0;L;;;;;N;;;;; +106BF;LINEAR A SIGN A515;Lo;0;L;;;;;N;;;;; +106C0;LINEAR A SIGN A516;Lo;0;L;;;;;N;;;;; +106C1;LINEAR A SIGN A520;Lo;0;L;;;;;N;;;;; +106C2;LINEAR A SIGN A521;Lo;0;L;;;;;N;;;;; +106C3;LINEAR A SIGN A523;Lo;0;L;;;;;N;;;;; +106C4;LINEAR A SIGN A524;Lo;0;L;;;;;N;;;;; +106C5;LINEAR A SIGN A525;Lo;0;L;;;;;N;;;;; +106C6;LINEAR A SIGN A526;Lo;0;L;;;;;N;;;;; +106C7;LINEAR A SIGN A527;Lo;0;L;;;;;N;;;;; +106C8;LINEAR A SIGN A528;Lo;0;L;;;;;N;;;;; +106C9;LINEAR A SIGN A529;Lo;0;L;;;;;N;;;;; +106CA;LINEAR A SIGN A530;Lo;0;L;;;;;N;;;;; +106CB;LINEAR A SIGN A531;Lo;0;L;;;;;N;;;;; +106CC;LINEAR A SIGN A532;Lo;0;L;;;;;N;;;;; +106CD;LINEAR A SIGN A534;Lo;0;L;;;;;N;;;;; +106CE;LINEAR A SIGN A535;Lo;0;L;;;;;N;;;;; +106CF;LINEAR A SIGN A536;Lo;0;L;;;;;N;;;;; +106D0;LINEAR A SIGN A537;Lo;0;L;;;;;N;;;;; +106D1;LINEAR A SIGN A538;Lo;0;L;;;;;N;;;;; +106D2;LINEAR A SIGN A539;Lo;0;L;;;;;N;;;;; +106D3;LINEAR A SIGN A540;Lo;0;L;;;;;N;;;;; +106D4;LINEAR A SIGN A541;Lo;0;L;;;;;N;;;;; +106D5;LINEAR A SIGN A542;Lo;0;L;;;;;N;;;;; +106D6;LINEAR A SIGN A545;Lo;0;L;;;;;N;;;;; +106D7;LINEAR A SIGN A547;Lo;0;L;;;;;N;;;;; +106D8;LINEAR A SIGN A548;Lo;0;L;;;;;N;;;;; +106D9;LINEAR A SIGN A549;Lo;0;L;;;;;N;;;;; +106DA;LINEAR A SIGN A550;Lo;0;L;;;;;N;;;;; +106DB;LINEAR A SIGN A551;Lo;0;L;;;;;N;;;;; +106DC;LINEAR A SIGN A552;Lo;0;L;;;;;N;;;;; +106DD;LINEAR A SIGN A553;Lo;0;L;;;;;N;;;;; +106DE;LINEAR A SIGN A554;Lo;0;L;;;;;N;;;;; +106DF;LINEAR A SIGN A555;Lo;0;L;;;;;N;;;;; +106E0;LINEAR A SIGN A556;Lo;0;L;;;;;N;;;;; +106E1;LINEAR A SIGN A557;Lo;0;L;;;;;N;;;;; +106E2;LINEAR A SIGN A559;Lo;0;L;;;;;N;;;;; +106E3;LINEAR A SIGN A563;Lo;0;L;;;;;N;;;;; +106E4;LINEAR A SIGN A564;Lo;0;L;;;;;N;;;;; +106E5;LINEAR A SIGN A565;Lo;0;L;;;;;N;;;;; +106E6;LINEAR A SIGN A566;Lo;0;L;;;;;N;;;;; +106E7;LINEAR A SIGN A568;Lo;0;L;;;;;N;;;;; +106E8;LINEAR A SIGN A569;Lo;0;L;;;;;N;;;;; +106E9;LINEAR A SIGN A570;Lo;0;L;;;;;N;;;;; +106EA;LINEAR A SIGN A571;Lo;0;L;;;;;N;;;;; +106EB;LINEAR A SIGN A572;Lo;0;L;;;;;N;;;;; +106EC;LINEAR A SIGN A573;Lo;0;L;;;;;N;;;;; +106ED;LINEAR A SIGN A574;Lo;0;L;;;;;N;;;;; +106EE;LINEAR A SIGN A575;Lo;0;L;;;;;N;;;;; +106EF;LINEAR A SIGN A576;Lo;0;L;;;;;N;;;;; +106F0;LINEAR A SIGN A577;Lo;0;L;;;;;N;;;;; +106F1;LINEAR A SIGN A578;Lo;0;L;;;;;N;;;;; +106F2;LINEAR A SIGN A579;Lo;0;L;;;;;N;;;;; +106F3;LINEAR A SIGN A580;Lo;0;L;;;;;N;;;;; +106F4;LINEAR A SIGN A581;Lo;0;L;;;;;N;;;;; +106F5;LINEAR A SIGN A582;Lo;0;L;;;;;N;;;;; +106F6;LINEAR A SIGN A583;Lo;0;L;;;;;N;;;;; +106F7;LINEAR A SIGN A584;Lo;0;L;;;;;N;;;;; +106F8;LINEAR A SIGN A585;Lo;0;L;;;;;N;;;;; +106F9;LINEAR A SIGN A586;Lo;0;L;;;;;N;;;;; +106FA;LINEAR A SIGN A587;Lo;0;L;;;;;N;;;;; +106FB;LINEAR A SIGN A588;Lo;0;L;;;;;N;;;;; +106FC;LINEAR A SIGN A589;Lo;0;L;;;;;N;;;;; +106FD;LINEAR A SIGN A591;Lo;0;L;;;;;N;;;;; +106FE;LINEAR A SIGN A592;Lo;0;L;;;;;N;;;;; +106FF;LINEAR A SIGN A594;Lo;0;L;;;;;N;;;;; +10700;LINEAR A SIGN A595;Lo;0;L;;;;;N;;;;; +10701;LINEAR A SIGN A596;Lo;0;L;;;;;N;;;;; +10702;LINEAR A SIGN A598;Lo;0;L;;;;;N;;;;; +10703;LINEAR A SIGN A600;Lo;0;L;;;;;N;;;;; +10704;LINEAR A SIGN A601;Lo;0;L;;;;;N;;;;; +10705;LINEAR A SIGN A602;Lo;0;L;;;;;N;;;;; +10706;LINEAR A SIGN A603;Lo;0;L;;;;;N;;;;; +10707;LINEAR A SIGN A604;Lo;0;L;;;;;N;;;;; +10708;LINEAR A SIGN A606;Lo;0;L;;;;;N;;;;; +10709;LINEAR A SIGN A608;Lo;0;L;;;;;N;;;;; +1070A;LINEAR A SIGN A609;Lo;0;L;;;;;N;;;;; +1070B;LINEAR A SIGN A610;Lo;0;L;;;;;N;;;;; +1070C;LINEAR A SIGN A611;Lo;0;L;;;;;N;;;;; +1070D;LINEAR A SIGN A612;Lo;0;L;;;;;N;;;;; +1070E;LINEAR A SIGN A613;Lo;0;L;;;;;N;;;;; +1070F;LINEAR A SIGN A614;Lo;0;L;;;;;N;;;;; +10710;LINEAR A SIGN A615;Lo;0;L;;;;;N;;;;; +10711;LINEAR A SIGN A616;Lo;0;L;;;;;N;;;;; +10712;LINEAR A SIGN A617;Lo;0;L;;;;;N;;;;; +10713;LINEAR A SIGN A618;Lo;0;L;;;;;N;;;;; +10714;LINEAR A SIGN A619;Lo;0;L;;;;;N;;;;; +10715;LINEAR A SIGN A620;Lo;0;L;;;;;N;;;;; +10716;LINEAR A SIGN A621;Lo;0;L;;;;;N;;;;; +10717;LINEAR A SIGN A622;Lo;0;L;;;;;N;;;;; +10718;LINEAR A SIGN A623;Lo;0;L;;;;;N;;;;; +10719;LINEAR A SIGN A624;Lo;0;L;;;;;N;;;;; +1071A;LINEAR A SIGN A626;Lo;0;L;;;;;N;;;;; +1071B;LINEAR A SIGN A627;Lo;0;L;;;;;N;;;;; +1071C;LINEAR A SIGN A628;Lo;0;L;;;;;N;;;;; +1071D;LINEAR A SIGN A629;Lo;0;L;;;;;N;;;;; +1071E;LINEAR A SIGN A634;Lo;0;L;;;;;N;;;;; +1071F;LINEAR A SIGN A637;Lo;0;L;;;;;N;;;;; +10720;LINEAR A SIGN A638;Lo;0;L;;;;;N;;;;; +10721;LINEAR A SIGN A640;Lo;0;L;;;;;N;;;;; +10722;LINEAR A SIGN A642;Lo;0;L;;;;;N;;;;; +10723;LINEAR A SIGN A643;Lo;0;L;;;;;N;;;;; +10724;LINEAR A SIGN A644;Lo;0;L;;;;;N;;;;; +10725;LINEAR A SIGN A645;Lo;0;L;;;;;N;;;;; +10726;LINEAR A SIGN A646;Lo;0;L;;;;;N;;;;; +10727;LINEAR A SIGN A648;Lo;0;L;;;;;N;;;;; +10728;LINEAR A SIGN A649;Lo;0;L;;;;;N;;;;; +10729;LINEAR A SIGN A651;Lo;0;L;;;;;N;;;;; +1072A;LINEAR A SIGN A652;Lo;0;L;;;;;N;;;;; +1072B;LINEAR A SIGN A653;Lo;0;L;;;;;N;;;;; +1072C;LINEAR A SIGN A654;Lo;0;L;;;;;N;;;;; +1072D;LINEAR A SIGN A655;Lo;0;L;;;;;N;;;;; +1072E;LINEAR A SIGN A656;Lo;0;L;;;;;N;;;;; +1072F;LINEAR A SIGN A657;Lo;0;L;;;;;N;;;;; +10730;LINEAR A SIGN A658;Lo;0;L;;;;;N;;;;; +10731;LINEAR A SIGN A659;Lo;0;L;;;;;N;;;;; +10732;LINEAR A SIGN A660;Lo;0;L;;;;;N;;;;; +10733;LINEAR A SIGN A661;Lo;0;L;;;;;N;;;;; +10734;LINEAR A SIGN A662;Lo;0;L;;;;;N;;;;; +10735;LINEAR A SIGN A663;Lo;0;L;;;;;N;;;;; +10736;LINEAR A SIGN A664;Lo;0;L;;;;;N;;;;; +10740;LINEAR A SIGN A701 A;Lo;0;L;;;;;N;;;;; +10741;LINEAR A SIGN A702 B;Lo;0;L;;;;;N;;;;; +10742;LINEAR A SIGN A703 D;Lo;0;L;;;;;N;;;;; +10743;LINEAR A SIGN A704 E;Lo;0;L;;;;;N;;;;; +10744;LINEAR A SIGN A705 F;Lo;0;L;;;;;N;;;;; +10745;LINEAR A SIGN A706 H;Lo;0;L;;;;;N;;;;; +10746;LINEAR A SIGN A707 J;Lo;0;L;;;;;N;;;;; +10747;LINEAR A SIGN A708 K;Lo;0;L;;;;;N;;;;; +10748;LINEAR A SIGN A709 L;Lo;0;L;;;;;N;;;;; +10749;LINEAR A SIGN A709-2 L2;Lo;0;L;;;;;N;;;;; +1074A;LINEAR A SIGN A709-3 L3;Lo;0;L;;;;;N;;;;; +1074B;LINEAR A SIGN A709-4 L4;Lo;0;L;;;;;N;;;;; +1074C;LINEAR A SIGN A709-6 L6;Lo;0;L;;;;;N;;;;; +1074D;LINEAR A SIGN A710 W;Lo;0;L;;;;;N;;;;; +1074E;LINEAR A SIGN A711 X;Lo;0;L;;;;;N;;;;; +1074F;LINEAR A SIGN A712 Y;Lo;0;L;;;;;N;;;;; +10750;LINEAR A SIGN A713 OMEGA;Lo;0;L;;;;;N;;;;; +10751;LINEAR A SIGN A714 ABB;Lo;0;L;;;;;N;;;;; +10752;LINEAR A SIGN A715 BB;Lo;0;L;;;;;N;;;;; +10753;LINEAR A SIGN A717 DD;Lo;0;L;;;;;N;;;;; +10754;LINEAR A SIGN A726 EYYY;Lo;0;L;;;;;N;;;;; +10755;LINEAR A SIGN A732 JE;Lo;0;L;;;;;N;;;;; +10760;LINEAR A SIGN A800;Lo;0;L;;;;;N;;;;; +10761;LINEAR A SIGN A801;Lo;0;L;;;;;N;;;;; +10762;LINEAR A SIGN A802;Lo;0;L;;;;;N;;;;; +10763;LINEAR A SIGN A803;Lo;0;L;;;;;N;;;;; +10764;LINEAR A SIGN A804;Lo;0;L;;;;;N;;;;; +10765;LINEAR A SIGN A805;Lo;0;L;;;;;N;;;;; +10766;LINEAR A SIGN A806;Lo;0;L;;;;;N;;;;; +10767;LINEAR A SIGN A807;Lo;0;L;;;;;N;;;;; 10800;CYPRIOT SYLLABLE A;Lo;0;R;;;;;N;;;;; 10801;CYPRIOT SYLLABLE E;Lo;0;R;;;;;N;;;;; 10802;CYPRIOT SYLLABLE I;Lo;0;R;;;;;N;;;;; @@ -16917,6 +17758,78 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1085D;IMPERIAL ARAMAIC NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; 1085E;IMPERIAL ARAMAIC NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; 1085F;IMPERIAL ARAMAIC NUMBER TEN THOUSAND;No;0;R;;;;10000;N;;;;; +10860;PALMYRENE LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10861;PALMYRENE LETTER BETH;Lo;0;R;;;;;N;;;;; +10862;PALMYRENE LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10863;PALMYRENE LETTER DALETH;Lo;0;R;;;;;N;;;;; +10864;PALMYRENE LETTER HE;Lo;0;R;;;;;N;;;;; +10865;PALMYRENE LETTER WAW;Lo;0;R;;;;;N;;;;; +10866;PALMYRENE LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10867;PALMYRENE LETTER HETH;Lo;0;R;;;;;N;;;;; +10868;PALMYRENE LETTER TETH;Lo;0;R;;;;;N;;;;; +10869;PALMYRENE LETTER YODH;Lo;0;R;;;;;N;;;;; +1086A;PALMYRENE LETTER KAPH;Lo;0;R;;;;;N;;;;; +1086B;PALMYRENE LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +1086C;PALMYRENE LETTER MEM;Lo;0;R;;;;;N;;;;; +1086D;PALMYRENE LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; +1086E;PALMYRENE LETTER NUN;Lo;0;R;;;;;N;;;;; +1086F;PALMYRENE LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10870;PALMYRENE LETTER AYIN;Lo;0;R;;;;;N;;;;; +10871;PALMYRENE LETTER PE;Lo;0;R;;;;;N;;;;; +10872;PALMYRENE LETTER SADHE;Lo;0;R;;;;;N;;;;; +10873;PALMYRENE LETTER QOPH;Lo;0;R;;;;;N;;;;; +10874;PALMYRENE LETTER RESH;Lo;0;R;;;;;N;;;;; +10875;PALMYRENE LETTER SHIN;Lo;0;R;;;;;N;;;;; +10876;PALMYRENE LETTER TAW;Lo;0;R;;;;;N;;;;; +10877;PALMYRENE LEFT-POINTING FLEURON;So;0;R;;;;;N;;;;; +10878;PALMYRENE RIGHT-POINTING FLEURON;So;0;R;;;;;N;;;;; +10879;PALMYRENE NUMBER ONE;No;0;R;;;;1;N;;;;; +1087A;PALMYRENE NUMBER TWO;No;0;R;;;;2;N;;;;; +1087B;PALMYRENE NUMBER THREE;No;0;R;;;;3;N;;;;; +1087C;PALMYRENE NUMBER FOUR;No;0;R;;;;4;N;;;;; +1087D;PALMYRENE NUMBER FIVE;No;0;R;;;;5;N;;;;; +1087E;PALMYRENE NUMBER TEN;No;0;R;;;;10;N;;;;; +1087F;PALMYRENE NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10880;NABATAEAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;; +10881;NABATAEAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10882;NABATAEAN LETTER FINAL BETH;Lo;0;R;;;;;N;;;;; +10883;NABATAEAN LETTER BETH;Lo;0;R;;;;;N;;;;; +10884;NABATAEAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10885;NABATAEAN LETTER DALETH;Lo;0;R;;;;;N;;;;; +10886;NABATAEAN LETTER FINAL HE;Lo;0;R;;;;;N;;;;; +10887;NABATAEAN LETTER HE;Lo;0;R;;;;;N;;;;; +10888;NABATAEAN LETTER WAW;Lo;0;R;;;;;N;;;;; +10889;NABATAEAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +1088A;NABATAEAN LETTER HETH;Lo;0;R;;;;;N;;;;; +1088B;NABATAEAN LETTER TETH;Lo;0;R;;;;;N;;;;; +1088C;NABATAEAN LETTER FINAL YODH;Lo;0;R;;;;;N;;;;; +1088D;NABATAEAN LETTER YODH;Lo;0;R;;;;;N;;;;; +1088E;NABATAEAN LETTER FINAL KAPH;Lo;0;R;;;;;N;;;;; +1088F;NABATAEAN LETTER KAPH;Lo;0;R;;;;;N;;;;; +10890;NABATAEAN LETTER FINAL LAMEDH;Lo;0;R;;;;;N;;;;; +10891;NABATAEAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10892;NABATAEAN LETTER FINAL MEM;Lo;0;R;;;;;N;;;;; +10893;NABATAEAN LETTER MEM;Lo;0;R;;;;;N;;;;; +10894;NABATAEAN LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; +10895;NABATAEAN LETTER NUN;Lo;0;R;;;;;N;;;;; +10896;NABATAEAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10897;NABATAEAN LETTER AYIN;Lo;0;R;;;;;N;;;;; +10898;NABATAEAN LETTER PE;Lo;0;R;;;;;N;;;;; +10899;NABATAEAN LETTER SADHE;Lo;0;R;;;;;N;;;;; +1089A;NABATAEAN LETTER QOPH;Lo;0;R;;;;;N;;;;; +1089B;NABATAEAN LETTER RESH;Lo;0;R;;;;;N;;;;; +1089C;NABATAEAN LETTER FINAL SHIN;Lo;0;R;;;;;N;;;;; +1089D;NABATAEAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +1089E;NABATAEAN LETTER TAW;Lo;0;R;;;;;N;;;;; +108A7;NABATAEAN NUMBER ONE;No;0;R;;;;1;N;;;;; +108A8;NABATAEAN NUMBER TWO;No;0;R;;;;2;N;;;;; +108A9;NABATAEAN NUMBER THREE;No;0;R;;;;3;N;;;;; +108AA;NABATAEAN NUMBER FOUR;No;0;R;;;;4;N;;;;; +108AB;NABATAEAN CRUCIFORM NUMBER FOUR;No;0;R;;;;4;N;;;;; +108AC;NABATAEAN NUMBER FIVE;No;0;R;;;;5;N;;;;; +108AD;NABATAEAN NUMBER TEN;No;0;R;;;;10;N;;;;; +108AE;NABATAEAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +108AF;NABATAEAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; 10900;PHOENICIAN LETTER ALF;Lo;0;R;;;;;N;;;;; 10901;PHOENICIAN LETTER BET;Lo;0;R;;;;;N;;;;; 10902;PHOENICIAN LETTER GAML;Lo;0;R;;;;;N;;;;; @@ -17128,6 +18041,89 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10A7D;OLD SOUTH ARABIAN NUMBER ONE;No;0;R;;;;1;N;;;;; 10A7E;OLD SOUTH ARABIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;; 10A7F;OLD SOUTH ARABIAN NUMERIC INDICATOR;Po;0;R;;;;;N;;;;; +10A80;OLD NORTH ARABIAN LETTER HEH;Lo;0;R;;;;;N;;;;; +10A81;OLD NORTH ARABIAN LETTER LAM;Lo;0;R;;;;;N;;;;; +10A82;OLD NORTH ARABIAN LETTER HAH;Lo;0;R;;;;;N;;;;; +10A83;OLD NORTH ARABIAN LETTER MEEM;Lo;0;R;;;;;N;;;;; +10A84;OLD NORTH ARABIAN LETTER QAF;Lo;0;R;;;;;N;;;;; +10A85;OLD NORTH ARABIAN LETTER WAW;Lo;0;R;;;;;N;;;;; +10A86;OLD NORTH ARABIAN LETTER ES-2;Lo;0;R;;;;;N;;;;; +10A87;OLD NORTH ARABIAN LETTER REH;Lo;0;R;;;;;N;;;;; +10A88;OLD NORTH ARABIAN LETTER BEH;Lo;0;R;;;;;N;;;;; +10A89;OLD NORTH ARABIAN LETTER TEH;Lo;0;R;;;;;N;;;;; +10A8A;OLD NORTH ARABIAN LETTER ES-1;Lo;0;R;;;;;N;;;;; +10A8B;OLD NORTH ARABIAN LETTER KAF;Lo;0;R;;;;;N;;;;; +10A8C;OLD NORTH ARABIAN LETTER NOON;Lo;0;R;;;;;N;;;;; +10A8D;OLD NORTH ARABIAN LETTER KHAH;Lo;0;R;;;;;N;;;;; +10A8E;OLD NORTH ARABIAN LETTER SAD;Lo;0;R;;;;;N;;;;; +10A8F;OLD NORTH ARABIAN LETTER ES-3;Lo;0;R;;;;;N;;;;; +10A90;OLD NORTH ARABIAN LETTER FEH;Lo;0;R;;;;;N;;;;; +10A91;OLD NORTH ARABIAN LETTER ALEF;Lo;0;R;;;;;N;;;;; +10A92;OLD NORTH ARABIAN LETTER AIN;Lo;0;R;;;;;N;;;;; +10A93;OLD NORTH ARABIAN LETTER DAD;Lo;0;R;;;;;N;;;;; +10A94;OLD NORTH ARABIAN LETTER GEEM;Lo;0;R;;;;;N;;;;; +10A95;OLD NORTH ARABIAN LETTER DAL;Lo;0;R;;;;;N;;;;; +10A96;OLD NORTH ARABIAN LETTER GHAIN;Lo;0;R;;;;;N;;;;; +10A97;OLD NORTH ARABIAN LETTER TAH;Lo;0;R;;;;;N;;;;; +10A98;OLD NORTH ARABIAN LETTER ZAIN;Lo;0;R;;;;;N;;;;; +10A99;OLD NORTH ARABIAN LETTER THAL;Lo;0;R;;;;;N;;;;; +10A9A;OLD NORTH ARABIAN LETTER YEH;Lo;0;R;;;;;N;;;;; +10A9B;OLD NORTH ARABIAN LETTER THEH;Lo;0;R;;;;;N;;;;; +10A9C;OLD NORTH ARABIAN LETTER ZAH;Lo;0;R;;;;;N;;;;; +10A9D;OLD NORTH ARABIAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10A9E;OLD NORTH ARABIAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10A9F;OLD NORTH ARABIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10AC0;MANICHAEAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10AC1;MANICHAEAN LETTER BETH;Lo;0;R;;;;;N;;;;; +10AC2;MANICHAEAN LETTER BHETH;Lo;0;R;;;;;N;;;;; +10AC3;MANICHAEAN LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10AC4;MANICHAEAN LETTER GHIMEL;Lo;0;R;;;;;N;;;;; +10AC5;MANICHAEAN LETTER DALETH;Lo;0;R;;;;;N;;;;; +10AC6;MANICHAEAN LETTER HE;Lo;0;R;;;;;N;;;;; +10AC7;MANICHAEAN LETTER WAW;Lo;0;R;;;;;N;;;;; +10AC8;MANICHAEAN SIGN UD;So;0;R;;;;;N;;;;; +10AC9;MANICHAEAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10ACA;MANICHAEAN LETTER ZHAYIN;Lo;0;R;;;;;N;;;;; +10ACB;MANICHAEAN LETTER JAYIN;Lo;0;R;;;;;N;;;;; +10ACC;MANICHAEAN LETTER JHAYIN;Lo;0;R;;;;;N;;;;; +10ACD;MANICHAEAN LETTER HETH;Lo;0;R;;;;;N;;;;; +10ACE;MANICHAEAN LETTER TETH;Lo;0;R;;;;;N;;;;; +10ACF;MANICHAEAN LETTER YODH;Lo;0;R;;;;;N;;;;; +10AD0;MANICHAEAN LETTER KAPH;Lo;0;R;;;;;N;;;;; +10AD1;MANICHAEAN LETTER XAPH;Lo;0;R;;;;;N;;;;; +10AD2;MANICHAEAN LETTER KHAPH;Lo;0;R;;;;;N;;;;; +10AD3;MANICHAEAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10AD4;MANICHAEAN LETTER DHAMEDH;Lo;0;R;;;;;N;;;;; +10AD5;MANICHAEAN LETTER THAMEDH;Lo;0;R;;;;;N;;;;; +10AD6;MANICHAEAN LETTER MEM;Lo;0;R;;;;;N;;;;; +10AD7;MANICHAEAN LETTER NUN;Lo;0;R;;;;;N;;;;; +10AD8;MANICHAEAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10AD9;MANICHAEAN LETTER AYIN;Lo;0;R;;;;;N;;;;; +10ADA;MANICHAEAN LETTER AAYIN;Lo;0;R;;;;;N;;;;; +10ADB;MANICHAEAN LETTER PE;Lo;0;R;;;;;N;;;;; +10ADC;MANICHAEAN LETTER FE;Lo;0;R;;;;;N;;;;; +10ADD;MANICHAEAN LETTER SADHE;Lo;0;R;;;;;N;;;;; +10ADE;MANICHAEAN LETTER QOPH;Lo;0;R;;;;;N;;;;; +10ADF;MANICHAEAN LETTER XOPH;Lo;0;R;;;;;N;;;;; +10AE0;MANICHAEAN LETTER QHOPH;Lo;0;R;;;;;N;;;;; +10AE1;MANICHAEAN LETTER RESH;Lo;0;R;;;;;N;;;;; +10AE2;MANICHAEAN LETTER SHIN;Lo;0;R;;;;;N;;;;; +10AE3;MANICHAEAN LETTER SSHIN;Lo;0;R;;;;;N;;;;; +10AE4;MANICHAEAN LETTER TAW;Lo;0;R;;;;;N;;;;; +10AE5;MANICHAEAN ABBREVIATION MARK ABOVE;Mn;230;NSM;;;;;N;;;;; +10AE6;MANICHAEAN ABBREVIATION MARK BELOW;Mn;220;NSM;;;;;N;;;;; +10AEB;MANICHAEAN NUMBER ONE;No;0;R;;;;1;N;;;;; +10AEC;MANICHAEAN NUMBER FIVE;No;0;R;;;;5;N;;;;; +10AED;MANICHAEAN NUMBER TEN;No;0;R;;;;10;N;;;;; +10AEE;MANICHAEAN NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10AEF;MANICHAEAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; +10AF0;MANICHAEAN PUNCTUATION STAR;Po;0;R;;;;;N;;;;; +10AF1;MANICHAEAN PUNCTUATION FLEURON;Po;0;R;;;;;N;;;;; +10AF2;MANICHAEAN PUNCTUATION DOUBLE DOT WITHIN DOT;Po;0;R;;;;;N;;;;; +10AF3;MANICHAEAN PUNCTUATION DOT WITHIN DOT;Po;0;R;;;;;N;;;;; +10AF4;MANICHAEAN PUNCTUATION DOT;Po;0;R;;;;;N;;;;; +10AF5;MANICHAEAN PUNCTUATION TWO DOTS;Po;0;R;;;;;N;;;;; +10AF6;MANICHAEAN PUNCTUATION LINE FILLER;Po;0;R;;;;;N;;;;; 10B00;AVESTAN LETTER A;Lo;0;R;;;;;N;;;;; 10B01;AVESTAN LETTER AA;Lo;0;R;;;;;N;;;;; 10B02;AVESTAN LETTER AO;Lo;0;R;;;;;N;;;;; @@ -17246,6 +18242,35 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10B7D;INSCRIPTIONAL PAHLAVI NUMBER TWENTY;No;0;R;;;;20;N;;;;; 10B7E;INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; 10B7F;INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;; +10B80;PSALTER PAHLAVI LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10B81;PSALTER PAHLAVI LETTER BETH;Lo;0;R;;;;;N;;;;; +10B82;PSALTER PAHLAVI LETTER GIMEL;Lo;0;R;;;;;N;;;;; +10B83;PSALTER PAHLAVI LETTER DALETH;Lo;0;R;;;;;N;;;;; +10B84;PSALTER PAHLAVI LETTER HE;Lo;0;R;;;;;N;;;;; +10B85;PSALTER PAHLAVI LETTER WAW-AYIN-RESH;Lo;0;R;;;;;N;;;;; +10B86;PSALTER PAHLAVI LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10B87;PSALTER PAHLAVI LETTER HETH;Lo;0;R;;;;;N;;;;; +10B88;PSALTER PAHLAVI LETTER YODH;Lo;0;R;;;;;N;;;;; +10B89;PSALTER PAHLAVI LETTER KAPH;Lo;0;R;;;;;N;;;;; +10B8A;PSALTER PAHLAVI LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10B8B;PSALTER PAHLAVI LETTER MEM-QOPH;Lo;0;R;;;;;N;;;;; +10B8C;PSALTER PAHLAVI LETTER NUN;Lo;0;R;;;;;N;;;;; +10B8D;PSALTER PAHLAVI LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10B8E;PSALTER PAHLAVI LETTER PE;Lo;0;R;;;;;N;;;;; +10B8F;PSALTER PAHLAVI LETTER SADHE;Lo;0;R;;;;;N;;;;; +10B90;PSALTER PAHLAVI LETTER SHIN;Lo;0;R;;;;;N;;;;; +10B91;PSALTER PAHLAVI LETTER TAW;Lo;0;R;;;;;N;;;;; +10B99;PSALTER PAHLAVI SECTION MARK;Po;0;R;;;;;N;;;;; +10B9A;PSALTER PAHLAVI TURNED SECTION MARK;Po;0;R;;;;;N;;;;; +10B9B;PSALTER PAHLAVI FOUR DOTS WITH CROSS;Po;0;R;;;;;N;;;;; +10B9C;PSALTER PAHLAVI FOUR DOTS WITH DOT;Po;0;R;;;;;N;;;;; +10BA9;PSALTER PAHLAVI NUMBER ONE;No;0;R;;;;1;N;;;;; +10BAA;PSALTER PAHLAVI NUMBER TWO;No;0;R;;;;2;N;;;;; +10BAB;PSALTER PAHLAVI NUMBER THREE;No;0;R;;;;3;N;;;;; +10BAC;PSALTER PAHLAVI NUMBER FOUR;No;0;R;;;;4;N;;;;; +10BAD;PSALTER PAHLAVI NUMBER TEN;No;0;R;;;;10;N;;;;; +10BAE;PSALTER PAHLAVI NUMBER TWENTY;No;0;R;;;;20;N;;;;; +10BAF;PSALTER PAHLAVI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;; 10C00;OLD TURKIC LETTER ORKHON A;Lo;0;R;;;;;N;;;;; 10C01;OLD TURKIC LETTER YENISEI A;Lo;0;R;;;;;N;;;;; 10C02;OLD TURKIC LETTER YENISEI AE;Lo;0;R;;;;;N;;;;; @@ -17458,6 +18483,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1106D;BRAHMI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 1106E;BRAHMI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 1106F;BRAHMI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1107F;BRAHMI NUMBER JOINER;Mn;9;NSM;;;;;N;;;;; 11080;KAITHI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 11081;KAITHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 11082;KAITHI SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -17626,6 +18652,45 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11141;CHAKMA DANDA;Po;0;L;;;;;N;;;;; 11142;CHAKMA DOUBLE DANDA;Po;0;L;;;;;N;;;;; 11143;CHAKMA QUESTION MARK;Po;0;L;;;;;N;;;;; +11150;MAHAJANI LETTER A;Lo;0;L;;;;;N;;;;; +11151;MAHAJANI LETTER I;Lo;0;L;;;;;N;;;;; +11152;MAHAJANI LETTER U;Lo;0;L;;;;;N;;;;; +11153;MAHAJANI LETTER E;Lo;0;L;;;;;N;;;;; +11154;MAHAJANI LETTER O;Lo;0;L;;;;;N;;;;; +11155;MAHAJANI LETTER KA;Lo;0;L;;;;;N;;;;; +11156;MAHAJANI LETTER KHA;Lo;0;L;;;;;N;;;;; +11157;MAHAJANI LETTER GA;Lo;0;L;;;;;N;;;;; +11158;MAHAJANI LETTER GHA;Lo;0;L;;;;;N;;;;; +11159;MAHAJANI LETTER CA;Lo;0;L;;;;;N;;;;; +1115A;MAHAJANI LETTER CHA;Lo;0;L;;;;;N;;;;; +1115B;MAHAJANI LETTER JA;Lo;0;L;;;;;N;;;;; +1115C;MAHAJANI LETTER JHA;Lo;0;L;;;;;N;;;;; +1115D;MAHAJANI LETTER NYA;Lo;0;L;;;;;N;;;;; +1115E;MAHAJANI LETTER TTA;Lo;0;L;;;;;N;;;;; +1115F;MAHAJANI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11160;MAHAJANI LETTER DDA;Lo;0;L;;;;;N;;;;; +11161;MAHAJANI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11162;MAHAJANI LETTER NNA;Lo;0;L;;;;;N;;;;; +11163;MAHAJANI LETTER TA;Lo;0;L;;;;;N;;;;; +11164;MAHAJANI LETTER THA;Lo;0;L;;;;;N;;;;; +11165;MAHAJANI LETTER DA;Lo;0;L;;;;;N;;;;; +11166;MAHAJANI LETTER DHA;Lo;0;L;;;;;N;;;;; +11167;MAHAJANI LETTER NA;Lo;0;L;;;;;N;;;;; +11168;MAHAJANI LETTER PA;Lo;0;L;;;;;N;;;;; +11169;MAHAJANI LETTER PHA;Lo;0;L;;;;;N;;;;; +1116A;MAHAJANI LETTER BA;Lo;0;L;;;;;N;;;;; +1116B;MAHAJANI LETTER BHA;Lo;0;L;;;;;N;;;;; +1116C;MAHAJANI LETTER MA;Lo;0;L;;;;;N;;;;; +1116D;MAHAJANI LETTER RA;Lo;0;L;;;;;N;;;;; +1116E;MAHAJANI LETTER LA;Lo;0;L;;;;;N;;;;; +1116F;MAHAJANI LETTER VA;Lo;0;L;;;;;N;;;;; +11170;MAHAJANI LETTER SA;Lo;0;L;;;;;N;;;;; +11171;MAHAJANI LETTER HA;Lo;0;L;;;;;N;;;;; +11172;MAHAJANI LETTER RRA;Lo;0;L;;;;;N;;;;; +11173;MAHAJANI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +11174;MAHAJANI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +11175;MAHAJANI SECTION MARK;Po;0;L;;;;;N;;;;; +11176;MAHAJANI LIGATURE SHRI;Lo;0;L;;;;;N;;;;; 11180;SHARADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 11181;SHARADA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 11182;SHARADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -17699,6 +18764,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 111C6;SHARADA DOUBLE DANDA;Po;0;L;;;;;N;;;;; 111C7;SHARADA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 111C8;SHARADA SEPARATOR;Po;0;L;;;;;N;;;;; +111CD;SHARADA SUTRA MARK;Po;0;L;;;;;N;;;;; 111D0;SHARADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 111D1;SHARADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 111D2;SHARADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -17709,6 +18775,473 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 111D7;SHARADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 111D8;SHARADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 111D9;SHARADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +111DA;SHARADA EKAM;Lo;0;L;;;;;N;;;;; +111E1;SINHALA ARCHAIC DIGIT ONE;No;0;L;;;;1;N;;;;; +111E2;SINHALA ARCHAIC DIGIT TWO;No;0;L;;;;2;N;;;;; +111E3;SINHALA ARCHAIC DIGIT THREE;No;0;L;;;;3;N;;;;; +111E4;SINHALA ARCHAIC DIGIT FOUR;No;0;L;;;;4;N;;;;; +111E5;SINHALA ARCHAIC DIGIT FIVE;No;0;L;;;;5;N;;;;; +111E6;SINHALA ARCHAIC DIGIT SIX;No;0;L;;;;6;N;;;;; +111E7;SINHALA ARCHAIC DIGIT SEVEN;No;0;L;;;;7;N;;;;; +111E8;SINHALA ARCHAIC DIGIT EIGHT;No;0;L;;;;8;N;;;;; +111E9;SINHALA ARCHAIC DIGIT NINE;No;0;L;;;;9;N;;;;; +111EA;SINHALA ARCHAIC NUMBER TEN;No;0;L;;;;10;N;;;;; +111EB;SINHALA ARCHAIC NUMBER TWENTY;No;0;L;;;;20;N;;;;; +111EC;SINHALA ARCHAIC NUMBER THIRTY;No;0;L;;;;30;N;;;;; +111ED;SINHALA ARCHAIC NUMBER FORTY;No;0;L;;;;40;N;;;;; +111EE;SINHALA ARCHAIC NUMBER FIFTY;No;0;L;;;;50;N;;;;; +111EF;SINHALA ARCHAIC NUMBER SIXTY;No;0;L;;;;60;N;;;;; +111F0;SINHALA ARCHAIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +111F1;SINHALA ARCHAIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +111F2;SINHALA ARCHAIC NUMBER NINETY;No;0;L;;;;90;N;;;;; +111F3;SINHALA ARCHAIC NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; +111F4;SINHALA ARCHAIC NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; +11200;KHOJKI LETTER A;Lo;0;L;;;;;N;;;;; +11201;KHOJKI LETTER AA;Lo;0;L;;;;;N;;;;; +11202;KHOJKI LETTER I;Lo;0;L;;;;;N;;;;; +11203;KHOJKI LETTER U;Lo;0;L;;;;;N;;;;; +11204;KHOJKI LETTER E;Lo;0;L;;;;;N;;;;; +11205;KHOJKI LETTER AI;Lo;0;L;;;;;N;;;;; +11206;KHOJKI LETTER O;Lo;0;L;;;;;N;;;;; +11207;KHOJKI LETTER AU;Lo;0;L;;;;;N;;;;; +11208;KHOJKI LETTER KA;Lo;0;L;;;;;N;;;;; +11209;KHOJKI LETTER KHA;Lo;0;L;;;;;N;;;;; +1120A;KHOJKI LETTER GA;Lo;0;L;;;;;N;;;;; +1120B;KHOJKI LETTER GGA;Lo;0;L;;;;;N;;;;; +1120C;KHOJKI LETTER GHA;Lo;0;L;;;;;N;;;;; +1120D;KHOJKI LETTER NGA;Lo;0;L;;;;;N;;;;; +1120E;KHOJKI LETTER CA;Lo;0;L;;;;;N;;;;; +1120F;KHOJKI LETTER CHA;Lo;0;L;;;;;N;;;;; +11210;KHOJKI LETTER JA;Lo;0;L;;;;;N;;;;; +11211;KHOJKI LETTER JJA;Lo;0;L;;;;;N;;;;; +11213;KHOJKI LETTER NYA;Lo;0;L;;;;;N;;;;; +11214;KHOJKI LETTER TTA;Lo;0;L;;;;;N;;;;; +11215;KHOJKI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11216;KHOJKI LETTER DDA;Lo;0;L;;;;;N;;;;; +11217;KHOJKI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11218;KHOJKI LETTER NNA;Lo;0;L;;;;;N;;;;; +11219;KHOJKI LETTER TA;Lo;0;L;;;;;N;;;;; +1121A;KHOJKI LETTER THA;Lo;0;L;;;;;N;;;;; +1121B;KHOJKI LETTER DA;Lo;0;L;;;;;N;;;;; +1121C;KHOJKI LETTER DDDA;Lo;0;L;;;;;N;;;;; +1121D;KHOJKI LETTER DHA;Lo;0;L;;;;;N;;;;; +1121E;KHOJKI LETTER NA;Lo;0;L;;;;;N;;;;; +1121F;KHOJKI LETTER PA;Lo;0;L;;;;;N;;;;; +11220;KHOJKI LETTER PHA;Lo;0;L;;;;;N;;;;; +11221;KHOJKI LETTER BA;Lo;0;L;;;;;N;;;;; +11222;KHOJKI LETTER BBA;Lo;0;L;;;;;N;;;;; +11223;KHOJKI LETTER BHA;Lo;0;L;;;;;N;;;;; +11224;KHOJKI LETTER MA;Lo;0;L;;;;;N;;;;; +11225;KHOJKI LETTER YA;Lo;0;L;;;;;N;;;;; +11226;KHOJKI LETTER RA;Lo;0;L;;;;;N;;;;; +11227;KHOJKI LETTER LA;Lo;0;L;;;;;N;;;;; +11228;KHOJKI LETTER VA;Lo;0;L;;;;;N;;;;; +11229;KHOJKI LETTER SA;Lo;0;L;;;;;N;;;;; +1122A;KHOJKI LETTER HA;Lo;0;L;;;;;N;;;;; +1122B;KHOJKI LETTER LLA;Lo;0;L;;;;;N;;;;; +1122C;KHOJKI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +1122D;KHOJKI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +1122E;KHOJKI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +1122F;KHOJKI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11230;KHOJKI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11231;KHOJKI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11232;KHOJKI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +11233;KHOJKI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +11234;KHOJKI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11235;KHOJKI SIGN VIRAMA;Mc;9;L;;;;;N;;;;; +11236;KHOJKI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +11237;KHOJKI SIGN SHADDA;Mn;0;NSM;;;;;N;;;;; +11238;KHOJKI DANDA;Po;0;L;;;;;N;;;;; +11239;KHOJKI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +1123A;KHOJKI WORD SEPARATOR;Po;0;L;;;;;N;;;;; +1123B;KHOJKI SECTION MARK;Po;0;L;;;;;N;;;;; +1123C;KHOJKI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; +1123D;KHOJKI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +112B0;KHUDAWADI LETTER A;Lo;0;L;;;;;N;;;;; +112B1;KHUDAWADI LETTER AA;Lo;0;L;;;;;N;;;;; +112B2;KHUDAWADI LETTER I;Lo;0;L;;;;;N;;;;; +112B3;KHUDAWADI LETTER II;Lo;0;L;;;;;N;;;;; +112B4;KHUDAWADI LETTER U;Lo;0;L;;;;;N;;;;; +112B5;KHUDAWADI LETTER UU;Lo;0;L;;;;;N;;;;; +112B6;KHUDAWADI LETTER E;Lo;0;L;;;;;N;;;;; +112B7;KHUDAWADI LETTER AI;Lo;0;L;;;;;N;;;;; +112B8;KHUDAWADI LETTER O;Lo;0;L;;;;;N;;;;; +112B9;KHUDAWADI LETTER AU;Lo;0;L;;;;;N;;;;; +112BA;KHUDAWADI LETTER KA;Lo;0;L;;;;;N;;;;; +112BB;KHUDAWADI LETTER KHA;Lo;0;L;;;;;N;;;;; +112BC;KHUDAWADI LETTER GA;Lo;0;L;;;;;N;;;;; +112BD;KHUDAWADI LETTER GGA;Lo;0;L;;;;;N;;;;; +112BE;KHUDAWADI LETTER GHA;Lo;0;L;;;;;N;;;;; +112BF;KHUDAWADI LETTER NGA;Lo;0;L;;;;;N;;;;; +112C0;KHUDAWADI LETTER CA;Lo;0;L;;;;;N;;;;; +112C1;KHUDAWADI LETTER CHA;Lo;0;L;;;;;N;;;;; +112C2;KHUDAWADI LETTER JA;Lo;0;L;;;;;N;;;;; +112C3;KHUDAWADI LETTER JJA;Lo;0;L;;;;;N;;;;; +112C4;KHUDAWADI LETTER JHA;Lo;0;L;;;;;N;;;;; +112C5;KHUDAWADI LETTER NYA;Lo;0;L;;;;;N;;;;; +112C6;KHUDAWADI LETTER TTA;Lo;0;L;;;;;N;;;;; +112C7;KHUDAWADI LETTER TTHA;Lo;0;L;;;;;N;;;;; +112C8;KHUDAWADI LETTER DDA;Lo;0;L;;;;;N;;;;; +112C9;KHUDAWADI LETTER DDDA;Lo;0;L;;;;;N;;;;; +112CA;KHUDAWADI LETTER RRA;Lo;0;L;;;;;N;;;;; +112CB;KHUDAWADI LETTER DDHA;Lo;0;L;;;;;N;;;;; +112CC;KHUDAWADI LETTER NNA;Lo;0;L;;;;;N;;;;; +112CD;KHUDAWADI LETTER TA;Lo;0;L;;;;;N;;;;; +112CE;KHUDAWADI LETTER THA;Lo;0;L;;;;;N;;;;; +112CF;KHUDAWADI LETTER DA;Lo;0;L;;;;;N;;;;; +112D0;KHUDAWADI LETTER DHA;Lo;0;L;;;;;N;;;;; +112D1;KHUDAWADI LETTER NA;Lo;0;L;;;;;N;;;;; +112D2;KHUDAWADI LETTER PA;Lo;0;L;;;;;N;;;;; +112D3;KHUDAWADI LETTER PHA;Lo;0;L;;;;;N;;;;; +112D4;KHUDAWADI LETTER BA;Lo;0;L;;;;;N;;;;; +112D5;KHUDAWADI LETTER BBA;Lo;0;L;;;;;N;;;;; +112D6;KHUDAWADI LETTER BHA;Lo;0;L;;;;;N;;;;; +112D7;KHUDAWADI LETTER MA;Lo;0;L;;;;;N;;;;; +112D8;KHUDAWADI LETTER YA;Lo;0;L;;;;;N;;;;; +112D9;KHUDAWADI LETTER RA;Lo;0;L;;;;;N;;;;; +112DA;KHUDAWADI LETTER LA;Lo;0;L;;;;;N;;;;; +112DB;KHUDAWADI LETTER VA;Lo;0;L;;;;;N;;;;; +112DC;KHUDAWADI LETTER SHA;Lo;0;L;;;;;N;;;;; +112DD;KHUDAWADI LETTER SA;Lo;0;L;;;;;N;;;;; +112DE;KHUDAWADI LETTER HA;Lo;0;L;;;;;N;;;;; +112DF;KHUDAWADI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +112E0;KHUDAWADI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +112E1;KHUDAWADI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +112E2;KHUDAWADI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +112E3;KHUDAWADI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +112E4;KHUDAWADI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +112E5;KHUDAWADI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +112E6;KHUDAWADI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +112E7;KHUDAWADI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +112E8;KHUDAWADI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +112E9;KHUDAWADI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +112EA;KHUDAWADI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +112F0;KHUDAWADI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +112F1;KHUDAWADI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +112F2;KHUDAWADI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +112F3;KHUDAWADI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +112F4;KHUDAWADI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +112F5;KHUDAWADI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +112F6;KHUDAWADI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +112F7;KHUDAWADI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +112F8;KHUDAWADI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +112F9;KHUDAWADI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11301;GRANTHA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11302;GRANTHA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +11303;GRANTHA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11305;GRANTHA LETTER A;Lo;0;L;;;;;N;;;;; +11306;GRANTHA LETTER AA;Lo;0;L;;;;;N;;;;; +11307;GRANTHA LETTER I;Lo;0;L;;;;;N;;;;; +11308;GRANTHA LETTER II;Lo;0;L;;;;;N;;;;; +11309;GRANTHA LETTER U;Lo;0;L;;;;;N;;;;; +1130A;GRANTHA LETTER UU;Lo;0;L;;;;;N;;;;; +1130B;GRANTHA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +1130C;GRANTHA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +1130F;GRANTHA LETTER EE;Lo;0;L;;;;;N;;;;; +11310;GRANTHA LETTER AI;Lo;0;L;;;;;N;;;;; +11313;GRANTHA LETTER OO;Lo;0;L;;;;;N;;;;; +11314;GRANTHA LETTER AU;Lo;0;L;;;;;N;;;;; +11315;GRANTHA LETTER KA;Lo;0;L;;;;;N;;;;; +11316;GRANTHA LETTER KHA;Lo;0;L;;;;;N;;;;; +11317;GRANTHA LETTER GA;Lo;0;L;;;;;N;;;;; +11318;GRANTHA LETTER GHA;Lo;0;L;;;;;N;;;;; +11319;GRANTHA LETTER NGA;Lo;0;L;;;;;N;;;;; +1131A;GRANTHA LETTER CA;Lo;0;L;;;;;N;;;;; +1131B;GRANTHA LETTER CHA;Lo;0;L;;;;;N;;;;; +1131C;GRANTHA LETTER JA;Lo;0;L;;;;;N;;;;; +1131D;GRANTHA LETTER JHA;Lo;0;L;;;;;N;;;;; +1131E;GRANTHA LETTER NYA;Lo;0;L;;;;;N;;;;; +1131F;GRANTHA LETTER TTA;Lo;0;L;;;;;N;;;;; +11320;GRANTHA LETTER TTHA;Lo;0;L;;;;;N;;;;; +11321;GRANTHA LETTER DDA;Lo;0;L;;;;;N;;;;; +11322;GRANTHA LETTER DDHA;Lo;0;L;;;;;N;;;;; +11323;GRANTHA LETTER NNA;Lo;0;L;;;;;N;;;;; +11324;GRANTHA LETTER TA;Lo;0;L;;;;;N;;;;; +11325;GRANTHA LETTER THA;Lo;0;L;;;;;N;;;;; +11326;GRANTHA LETTER DA;Lo;0;L;;;;;N;;;;; +11327;GRANTHA LETTER DHA;Lo;0;L;;;;;N;;;;; +11328;GRANTHA LETTER NA;Lo;0;L;;;;;N;;;;; +1132A;GRANTHA LETTER PA;Lo;0;L;;;;;N;;;;; +1132B;GRANTHA LETTER PHA;Lo;0;L;;;;;N;;;;; +1132C;GRANTHA LETTER BA;Lo;0;L;;;;;N;;;;; +1132D;GRANTHA LETTER BHA;Lo;0;L;;;;;N;;;;; +1132E;GRANTHA LETTER MA;Lo;0;L;;;;;N;;;;; +1132F;GRANTHA LETTER YA;Lo;0;L;;;;;N;;;;; +11330;GRANTHA LETTER RA;Lo;0;L;;;;;N;;;;; +11332;GRANTHA LETTER LA;Lo;0;L;;;;;N;;;;; +11333;GRANTHA LETTER LLA;Lo;0;L;;;;;N;;;;; +11335;GRANTHA LETTER VA;Lo;0;L;;;;;N;;;;; +11336;GRANTHA LETTER SHA;Lo;0;L;;;;;N;;;;; +11337;GRANTHA LETTER SSA;Lo;0;L;;;;;N;;;;; +11338;GRANTHA LETTER SA;Lo;0;L;;;;;N;;;;; +11339;GRANTHA LETTER HA;Lo;0;L;;;;;N;;;;; +1133C;GRANTHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +1133D;GRANTHA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +1133E;GRANTHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +1133F;GRANTHA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11340;GRANTHA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +11341;GRANTHA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +11342;GRANTHA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +11343;GRANTHA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +11344;GRANTHA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +11347;GRANTHA VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +11348;GRANTHA VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +1134B;GRANTHA VOWEL SIGN OO;Mc;0;L;11347 1133E;;;;N;;;;; +1134C;GRANTHA VOWEL SIGN AU;Mc;0;L;11347 11357;;;;N;;;;; +1134D;GRANTHA SIGN VIRAMA;Mc;9;L;;;;;N;;;;; +11357;GRANTHA AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +1135D;GRANTHA SIGN PLUTA;Lo;0;L;;;;;N;;;;; +1135E;GRANTHA LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; +1135F;GRANTHA LETTER VEDIC DOUBLE ANUSVARA;Lo;0;L;;;;;N;;;;; +11360;GRANTHA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11361;GRANTHA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +11362;GRANTHA VOWEL SIGN VOCALIC L;Mc;0;L;;;;;N;;;;; +11363;GRANTHA VOWEL SIGN VOCALIC LL;Mc;0;L;;;;;N;;;;; +11366;COMBINING GRANTHA DIGIT ZERO;Mn;230;NSM;;;;;N;;;;; +11367;COMBINING GRANTHA DIGIT ONE;Mn;230;NSM;;;;;N;;;;; +11368;COMBINING GRANTHA DIGIT TWO;Mn;230;NSM;;;;;N;;;;; +11369;COMBINING GRANTHA DIGIT THREE;Mn;230;NSM;;;;;N;;;;; +1136A;COMBINING GRANTHA DIGIT FOUR;Mn;230;NSM;;;;;N;;;;; +1136B;COMBINING GRANTHA DIGIT FIVE;Mn;230;NSM;;;;;N;;;;; +1136C;COMBINING GRANTHA DIGIT SIX;Mn;230;NSM;;;;;N;;;;; +11370;COMBINING GRANTHA LETTER A;Mn;230;NSM;;;;;N;;;;; +11371;COMBINING GRANTHA LETTER KA;Mn;230;NSM;;;;;N;;;;; +11372;COMBINING GRANTHA LETTER NA;Mn;230;NSM;;;;;N;;;;; +11373;COMBINING GRANTHA LETTER VI;Mn;230;NSM;;;;;N;;;;; +11374;COMBINING GRANTHA LETTER PA;Mn;230;NSM;;;;;N;;;;; +11480;TIRHUTA ANJI;Lo;0;L;;;;;N;;;;; +11481;TIRHUTA LETTER A;Lo;0;L;;;;;N;;;;; +11482;TIRHUTA LETTER AA;Lo;0;L;;;;;N;;;;; +11483;TIRHUTA LETTER I;Lo;0;L;;;;;N;;;;; +11484;TIRHUTA LETTER II;Lo;0;L;;;;;N;;;;; +11485;TIRHUTA LETTER U;Lo;0;L;;;;;N;;;;; +11486;TIRHUTA LETTER UU;Lo;0;L;;;;;N;;;;; +11487;TIRHUTA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11488;TIRHUTA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11489;TIRHUTA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +1148A;TIRHUTA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1148B;TIRHUTA LETTER E;Lo;0;L;;;;;N;;;;; +1148C;TIRHUTA LETTER AI;Lo;0;L;;;;;N;;;;; +1148D;TIRHUTA LETTER O;Lo;0;L;;;;;N;;;;; +1148E;TIRHUTA LETTER AU;Lo;0;L;;;;;N;;;;; +1148F;TIRHUTA LETTER KA;Lo;0;L;;;;;N;;;;; +11490;TIRHUTA LETTER KHA;Lo;0;L;;;;;N;;;;; +11491;TIRHUTA LETTER GA;Lo;0;L;;;;;N;;;;; +11492;TIRHUTA LETTER GHA;Lo;0;L;;;;;N;;;;; +11493;TIRHUTA LETTER NGA;Lo;0;L;;;;;N;;;;; +11494;TIRHUTA LETTER CA;Lo;0;L;;;;;N;;;;; +11495;TIRHUTA LETTER CHA;Lo;0;L;;;;;N;;;;; +11496;TIRHUTA LETTER JA;Lo;0;L;;;;;N;;;;; +11497;TIRHUTA LETTER JHA;Lo;0;L;;;;;N;;;;; +11498;TIRHUTA LETTER NYA;Lo;0;L;;;;;N;;;;; +11499;TIRHUTA LETTER TTA;Lo;0;L;;;;;N;;;;; +1149A;TIRHUTA LETTER TTHA;Lo;0;L;;;;;N;;;;; +1149B;TIRHUTA LETTER DDA;Lo;0;L;;;;;N;;;;; +1149C;TIRHUTA LETTER DDHA;Lo;0;L;;;;;N;;;;; +1149D;TIRHUTA LETTER NNA;Lo;0;L;;;;;N;;;;; +1149E;TIRHUTA LETTER TA;Lo;0;L;;;;;N;;;;; +1149F;TIRHUTA LETTER THA;Lo;0;L;;;;;N;;;;; +114A0;TIRHUTA LETTER DA;Lo;0;L;;;;;N;;;;; +114A1;TIRHUTA LETTER DHA;Lo;0;L;;;;;N;;;;; +114A2;TIRHUTA LETTER NA;Lo;0;L;;;;;N;;;;; +114A3;TIRHUTA LETTER PA;Lo;0;L;;;;;N;;;;; +114A4;TIRHUTA LETTER PHA;Lo;0;L;;;;;N;;;;; +114A5;TIRHUTA LETTER BA;Lo;0;L;;;;;N;;;;; +114A6;TIRHUTA LETTER BHA;Lo;0;L;;;;;N;;;;; +114A7;TIRHUTA LETTER MA;Lo;0;L;;;;;N;;;;; +114A8;TIRHUTA LETTER YA;Lo;0;L;;;;;N;;;;; +114A9;TIRHUTA LETTER RA;Lo;0;L;;;;;N;;;;; +114AA;TIRHUTA LETTER LA;Lo;0;L;;;;;N;;;;; +114AB;TIRHUTA LETTER VA;Lo;0;L;;;;;N;;;;; +114AC;TIRHUTA LETTER SHA;Lo;0;L;;;;;N;;;;; +114AD;TIRHUTA LETTER SSA;Lo;0;L;;;;;N;;;;; +114AE;TIRHUTA LETTER SA;Lo;0;L;;;;;N;;;;; +114AF;TIRHUTA LETTER HA;Lo;0;L;;;;;N;;;;; +114B0;TIRHUTA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +114B1;TIRHUTA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +114B2;TIRHUTA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +114B3;TIRHUTA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +114B4;TIRHUTA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +114B5;TIRHUTA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +114B6;TIRHUTA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +114B7;TIRHUTA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +114B8;TIRHUTA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +114B9;TIRHUTA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +114BA;TIRHUTA VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;; +114BB;TIRHUTA VOWEL SIGN AI;Mc;0;L;114B9 114BA;;;;N;;;;; +114BC;TIRHUTA VOWEL SIGN O;Mc;0;L;114B9 114B0;;;;N;;;;; +114BD;TIRHUTA VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;; +114BE;TIRHUTA VOWEL SIGN AU;Mc;0;L;114B9 114BD;;;;N;;;;; +114BF;TIRHUTA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +114C0;TIRHUTA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +114C1;TIRHUTA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +114C2;TIRHUTA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +114C3;TIRHUTA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +114C4;TIRHUTA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +114C5;TIRHUTA GVANG;Lo;0;L;;;;;N;;;;; +114C6;TIRHUTA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +114C7;TIRHUTA OM;Lo;0;L;;;;;N;;;;; +114D0;TIRHUTA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +114D1;TIRHUTA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +114D2;TIRHUTA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +114D3;TIRHUTA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +114D4;TIRHUTA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +114D5;TIRHUTA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +114D6;TIRHUTA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +114D7;TIRHUTA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +114D8;TIRHUTA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +114D9;TIRHUTA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11580;SIDDHAM LETTER A;Lo;0;L;;;;;N;;;;; +11581;SIDDHAM LETTER AA;Lo;0;L;;;;;N;;;;; +11582;SIDDHAM LETTER I;Lo;0;L;;;;;N;;;;; +11583;SIDDHAM LETTER II;Lo;0;L;;;;;N;;;;; +11584;SIDDHAM LETTER U;Lo;0;L;;;;;N;;;;; +11585;SIDDHAM LETTER UU;Lo;0;L;;;;;N;;;;; +11586;SIDDHAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11587;SIDDHAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11588;SIDDHAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11589;SIDDHAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1158A;SIDDHAM LETTER E;Lo;0;L;;;;;N;;;;; +1158B;SIDDHAM LETTER AI;Lo;0;L;;;;;N;;;;; +1158C;SIDDHAM LETTER O;Lo;0;L;;;;;N;;;;; +1158D;SIDDHAM LETTER AU;Lo;0;L;;;;;N;;;;; +1158E;SIDDHAM LETTER KA;Lo;0;L;;;;;N;;;;; +1158F;SIDDHAM LETTER KHA;Lo;0;L;;;;;N;;;;; +11590;SIDDHAM LETTER GA;Lo;0;L;;;;;N;;;;; +11591;SIDDHAM LETTER GHA;Lo;0;L;;;;;N;;;;; +11592;SIDDHAM LETTER NGA;Lo;0;L;;;;;N;;;;; +11593;SIDDHAM LETTER CA;Lo;0;L;;;;;N;;;;; +11594;SIDDHAM LETTER CHA;Lo;0;L;;;;;N;;;;; +11595;SIDDHAM LETTER JA;Lo;0;L;;;;;N;;;;; +11596;SIDDHAM LETTER JHA;Lo;0;L;;;;;N;;;;; +11597;SIDDHAM LETTER NYA;Lo;0;L;;;;;N;;;;; +11598;SIDDHAM LETTER TTA;Lo;0;L;;;;;N;;;;; +11599;SIDDHAM LETTER TTHA;Lo;0;L;;;;;N;;;;; +1159A;SIDDHAM LETTER DDA;Lo;0;L;;;;;N;;;;; +1159B;SIDDHAM LETTER DDHA;Lo;0;L;;;;;N;;;;; +1159C;SIDDHAM LETTER NNA;Lo;0;L;;;;;N;;;;; +1159D;SIDDHAM LETTER TA;Lo;0;L;;;;;N;;;;; +1159E;SIDDHAM LETTER THA;Lo;0;L;;;;;N;;;;; +1159F;SIDDHAM LETTER DA;Lo;0;L;;;;;N;;;;; +115A0;SIDDHAM LETTER DHA;Lo;0;L;;;;;N;;;;; +115A1;SIDDHAM LETTER NA;Lo;0;L;;;;;N;;;;; +115A2;SIDDHAM LETTER PA;Lo;0;L;;;;;N;;;;; +115A3;SIDDHAM LETTER PHA;Lo;0;L;;;;;N;;;;; +115A4;SIDDHAM LETTER BA;Lo;0;L;;;;;N;;;;; +115A5;SIDDHAM LETTER BHA;Lo;0;L;;;;;N;;;;; +115A6;SIDDHAM LETTER MA;Lo;0;L;;;;;N;;;;; +115A7;SIDDHAM LETTER YA;Lo;0;L;;;;;N;;;;; +115A8;SIDDHAM LETTER RA;Lo;0;L;;;;;N;;;;; +115A9;SIDDHAM LETTER LA;Lo;0;L;;;;;N;;;;; +115AA;SIDDHAM LETTER VA;Lo;0;L;;;;;N;;;;; +115AB;SIDDHAM LETTER SHA;Lo;0;L;;;;;N;;;;; +115AC;SIDDHAM LETTER SSA;Lo;0;L;;;;;N;;;;; +115AD;SIDDHAM LETTER SA;Lo;0;L;;;;;N;;;;; +115AE;SIDDHAM LETTER HA;Lo;0;L;;;;;N;;;;; +115AF;SIDDHAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +115B0;SIDDHAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +115B1;SIDDHAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +115B2;SIDDHAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +115B3;SIDDHAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +115B4;SIDDHAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +115B5;SIDDHAM VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +115B8;SIDDHAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +115B9;SIDDHAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +115BA;SIDDHAM VOWEL SIGN O;Mc;0;L;115B8 115AF;;;;N;;;;; +115BB;SIDDHAM VOWEL SIGN AU;Mc;0;L;115B9 115AF;;;;N;;;;; +115BC;SIDDHAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +115BD;SIDDHAM SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +115BE;SIDDHAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; +115BF;SIDDHAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +115C0;SIDDHAM SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +115C1;SIDDHAM SIGN SIDDHAM;Po;0;L;;;;;N;;;;; +115C2;SIDDHAM DANDA;Po;0;L;;;;;N;;;;; +115C3;SIDDHAM DOUBLE DANDA;Po;0;L;;;;;N;;;;; +115C4;SIDDHAM SEPARATOR DOT;Po;0;L;;;;;N;;;;; +115C5;SIDDHAM SEPARATOR BAR;Po;0;L;;;;;N;;;;; +115C6;SIDDHAM REPETITION MARK-1;Po;0;L;;;;;N;;;;; +115C7;SIDDHAM REPETITION MARK-2;Po;0;L;;;;;N;;;;; +115C8;SIDDHAM REPETITION MARK-3;Po;0;L;;;;;N;;;;; +115C9;SIDDHAM END OF TEXT MARK;Po;0;L;;;;;N;;;;; +11600;MODI LETTER A;Lo;0;L;;;;;N;;;;; +11601;MODI LETTER AA;Lo;0;L;;;;;N;;;;; +11602;MODI LETTER I;Lo;0;L;;;;;N;;;;; +11603;MODI LETTER II;Lo;0;L;;;;;N;;;;; +11604;MODI LETTER U;Lo;0;L;;;;;N;;;;; +11605;MODI LETTER UU;Lo;0;L;;;;;N;;;;; +11606;MODI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11607;MODI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11608;MODI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11609;MODI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1160A;MODI LETTER E;Lo;0;L;;;;;N;;;;; +1160B;MODI LETTER AI;Lo;0;L;;;;;N;;;;; +1160C;MODI LETTER O;Lo;0;L;;;;;N;;;;; +1160D;MODI LETTER AU;Lo;0;L;;;;;N;;;;; +1160E;MODI LETTER KA;Lo;0;L;;;;;N;;;;; +1160F;MODI LETTER KHA;Lo;0;L;;;;;N;;;;; +11610;MODI LETTER GA;Lo;0;L;;;;;N;;;;; +11611;MODI LETTER GHA;Lo;0;L;;;;;N;;;;; +11612;MODI LETTER NGA;Lo;0;L;;;;;N;;;;; +11613;MODI LETTER CA;Lo;0;L;;;;;N;;;;; +11614;MODI LETTER CHA;Lo;0;L;;;;;N;;;;; +11615;MODI LETTER JA;Lo;0;L;;;;;N;;;;; +11616;MODI LETTER JHA;Lo;0;L;;;;;N;;;;; +11617;MODI LETTER NYA;Lo;0;L;;;;;N;;;;; +11618;MODI LETTER TTA;Lo;0;L;;;;;N;;;;; +11619;MODI LETTER TTHA;Lo;0;L;;;;;N;;;;; +1161A;MODI LETTER DDA;Lo;0;L;;;;;N;;;;; +1161B;MODI LETTER DDHA;Lo;0;L;;;;;N;;;;; +1161C;MODI LETTER NNA;Lo;0;L;;;;;N;;;;; +1161D;MODI LETTER TA;Lo;0;L;;;;;N;;;;; +1161E;MODI LETTER THA;Lo;0;L;;;;;N;;;;; +1161F;MODI LETTER DA;Lo;0;L;;;;;N;;;;; +11620;MODI LETTER DHA;Lo;0;L;;;;;N;;;;; +11621;MODI LETTER NA;Lo;0;L;;;;;N;;;;; +11622;MODI LETTER PA;Lo;0;L;;;;;N;;;;; +11623;MODI LETTER PHA;Lo;0;L;;;;;N;;;;; +11624;MODI LETTER BA;Lo;0;L;;;;;N;;;;; +11625;MODI LETTER BHA;Lo;0;L;;;;;N;;;;; +11626;MODI LETTER MA;Lo;0;L;;;;;N;;;;; +11627;MODI LETTER YA;Lo;0;L;;;;;N;;;;; +11628;MODI LETTER RA;Lo;0;L;;;;;N;;;;; +11629;MODI LETTER LA;Lo;0;L;;;;;N;;;;; +1162A;MODI LETTER VA;Lo;0;L;;;;;N;;;;; +1162B;MODI LETTER SHA;Lo;0;L;;;;;N;;;;; +1162C;MODI LETTER SSA;Lo;0;L;;;;;N;;;;; +1162D;MODI LETTER SA;Lo;0;L;;;;;N;;;;; +1162E;MODI LETTER HA;Lo;0;L;;;;;N;;;;; +1162F;MODI LETTER LLA;Lo;0;L;;;;;N;;;;; +11630;MODI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11631;MODI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11632;MODI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +11633;MODI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11634;MODI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11635;MODI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11636;MODI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +11637;MODI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +11638;MODI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +11639;MODI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +1163A;MODI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +1163B;MODI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +1163C;MODI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +1163D;MODI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +1163E;MODI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +1163F;MODI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +11640;MODI SIGN ARDHACANDRA;Mn;0;NSM;;;;;N;;;;; +11641;MODI DANDA;Po;0;L;;;;;N;;;;; +11642;MODI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11643;MODI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +11644;MODI SIGN HUVA;Lo;0;L;;;;;N;;;;; +11650;MODI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11651;MODI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11652;MODI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11653;MODI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11654;MODI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11655;MODI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11656;MODI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11657;MODI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11658;MODI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11659;MODI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 11680;TAKRI LETTER A;Lo;0;L;;;;;N;;;;; 11681;TAKRI LETTER AA;Lo;0;L;;;;;N;;;;; 11682;TAKRI LETTER I;Lo;0;L;;;;;N;;;;; @@ -17775,6 +19308,147 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 116C7;TAKRI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 116C8;TAKRI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 116C9;TAKRI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +118A0;WARANG CITI CAPITAL LETTER NGAA;Lu;0;L;;;;;N;;;;118C0; +118A1;WARANG CITI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;118C1; +118A2;WARANG CITI CAPITAL LETTER WI;Lu;0;L;;;;;N;;;;118C2; +118A3;WARANG CITI CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;118C3; +118A4;WARANG CITI CAPITAL LETTER YA;Lu;0;L;;;;;N;;;;118C4; +118A5;WARANG CITI CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;118C5; +118A6;WARANG CITI CAPITAL LETTER II;Lu;0;L;;;;;N;;;;118C6; +118A7;WARANG CITI CAPITAL LETTER UU;Lu;0;L;;;;;N;;;;118C7; +118A8;WARANG CITI CAPITAL LETTER E;Lu;0;L;;;;;N;;;;118C8; +118A9;WARANG CITI CAPITAL LETTER O;Lu;0;L;;;;;N;;;;118C9; +118AA;WARANG CITI CAPITAL LETTER ANG;Lu;0;L;;;;;N;;;;118CA; +118AB;WARANG CITI CAPITAL LETTER GA;Lu;0;L;;;;;N;;;;118CB; +118AC;WARANG CITI CAPITAL LETTER KO;Lu;0;L;;;;;N;;;;118CC; +118AD;WARANG CITI CAPITAL LETTER ENY;Lu;0;L;;;;;N;;;;118CD; +118AE;WARANG CITI CAPITAL LETTER YUJ;Lu;0;L;;;;;N;;;;118CE; +118AF;WARANG CITI CAPITAL LETTER UC;Lu;0;L;;;;;N;;;;118CF; +118B0;WARANG CITI CAPITAL LETTER ENN;Lu;0;L;;;;;N;;;;118D0; +118B1;WARANG CITI CAPITAL LETTER ODD;Lu;0;L;;;;;N;;;;118D1; +118B2;WARANG CITI CAPITAL LETTER TTE;Lu;0;L;;;;;N;;;;118D2; +118B3;WARANG CITI CAPITAL LETTER NUNG;Lu;0;L;;;;;N;;;;118D3; +118B4;WARANG CITI CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;118D4; +118B5;WARANG CITI CAPITAL LETTER AT;Lu;0;L;;;;;N;;;;118D5; +118B6;WARANG CITI CAPITAL LETTER AM;Lu;0;L;;;;;N;;;;118D6; +118B7;WARANG CITI CAPITAL LETTER BU;Lu;0;L;;;;;N;;;;118D7; +118B8;WARANG CITI CAPITAL LETTER PU;Lu;0;L;;;;;N;;;;118D8; +118B9;WARANG CITI CAPITAL LETTER HIYO;Lu;0;L;;;;;N;;;;118D9; +118BA;WARANG CITI CAPITAL LETTER HOLO;Lu;0;L;;;;;N;;;;118DA; +118BB;WARANG CITI CAPITAL LETTER HORR;Lu;0;L;;;;;N;;;;118DB; +118BC;WARANG CITI CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;118DC; +118BD;WARANG CITI CAPITAL LETTER SSUU;Lu;0;L;;;;;N;;;;118DD; +118BE;WARANG CITI CAPITAL LETTER SII;Lu;0;L;;;;;N;;;;118DE; +118BF;WARANG CITI CAPITAL LETTER VIYO;Lu;0;L;;;;;N;;;;118DF; +118C0;WARANG CITI SMALL LETTER NGAA;Ll;0;L;;;;;N;;;118A0;;118A0 +118C1;WARANG CITI SMALL LETTER A;Ll;0;L;;;;;N;;;118A1;;118A1 +118C2;WARANG CITI SMALL LETTER WI;Ll;0;L;;;;;N;;;118A2;;118A2 +118C3;WARANG CITI SMALL LETTER YU;Ll;0;L;;;;;N;;;118A3;;118A3 +118C4;WARANG CITI SMALL LETTER YA;Ll;0;L;;;;;N;;;118A4;;118A4 +118C5;WARANG CITI SMALL LETTER YO;Ll;0;L;;;;;N;;;118A5;;118A5 +118C6;WARANG CITI SMALL LETTER II;Ll;0;L;;;;;N;;;118A6;;118A6 +118C7;WARANG CITI SMALL LETTER UU;Ll;0;L;;;;;N;;;118A7;;118A7 +118C8;WARANG CITI SMALL LETTER E;Ll;0;L;;;;;N;;;118A8;;118A8 +118C9;WARANG CITI SMALL LETTER O;Ll;0;L;;;;;N;;;118A9;;118A9 +118CA;WARANG CITI SMALL LETTER ANG;Ll;0;L;;;;;N;;;118AA;;118AA +118CB;WARANG CITI SMALL LETTER GA;Ll;0;L;;;;;N;;;118AB;;118AB +118CC;WARANG CITI SMALL LETTER KO;Ll;0;L;;;;;N;;;118AC;;118AC +118CD;WARANG CITI SMALL LETTER ENY;Ll;0;L;;;;;N;;;118AD;;118AD +118CE;WARANG CITI SMALL LETTER YUJ;Ll;0;L;;;;;N;;;118AE;;118AE +118CF;WARANG CITI SMALL LETTER UC;Ll;0;L;;;;;N;;;118AF;;118AF +118D0;WARANG CITI SMALL LETTER ENN;Ll;0;L;;;;;N;;;118B0;;118B0 +118D1;WARANG CITI SMALL LETTER ODD;Ll;0;L;;;;;N;;;118B1;;118B1 +118D2;WARANG CITI SMALL LETTER TTE;Ll;0;L;;;;;N;;;118B2;;118B2 +118D3;WARANG CITI SMALL LETTER NUNG;Ll;0;L;;;;;N;;;118B3;;118B3 +118D4;WARANG CITI SMALL LETTER DA;Ll;0;L;;;;;N;;;118B4;;118B4 +118D5;WARANG CITI SMALL LETTER AT;Ll;0;L;;;;;N;;;118B5;;118B5 +118D6;WARANG CITI SMALL LETTER AM;Ll;0;L;;;;;N;;;118B6;;118B6 +118D7;WARANG CITI SMALL LETTER BU;Ll;0;L;;;;;N;;;118B7;;118B7 +118D8;WARANG CITI SMALL LETTER PU;Ll;0;L;;;;;N;;;118B8;;118B8 +118D9;WARANG CITI SMALL LETTER HIYO;Ll;0;L;;;;;N;;;118B9;;118B9 +118DA;WARANG CITI SMALL LETTER HOLO;Ll;0;L;;;;;N;;;118BA;;118BA +118DB;WARANG CITI SMALL LETTER HORR;Ll;0;L;;;;;N;;;118BB;;118BB +118DC;WARANG CITI SMALL LETTER HAR;Ll;0;L;;;;;N;;;118BC;;118BC +118DD;WARANG CITI SMALL LETTER SSUU;Ll;0;L;;;;;N;;;118BD;;118BD +118DE;WARANG CITI SMALL LETTER SII;Ll;0;L;;;;;N;;;118BE;;118BE +118DF;WARANG CITI SMALL LETTER VIYO;Ll;0;L;;;;;N;;;118BF;;118BF +118E0;WARANG CITI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +118E1;WARANG CITI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +118E2;WARANG CITI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +118E3;WARANG CITI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +118E4;WARANG CITI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +118E5;WARANG CITI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +118E6;WARANG CITI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +118E7;WARANG CITI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +118E8;WARANG CITI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +118E9;WARANG CITI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +118EA;WARANG CITI NUMBER TEN;No;0;L;;;;10;N;;;;; +118EB;WARANG CITI NUMBER TWENTY;No;0;L;;;;20;N;;;;; +118EC;WARANG CITI NUMBER THIRTY;No;0;L;;;;30;N;;;;; +118ED;WARANG CITI NUMBER FORTY;No;0;L;;;;40;N;;;;; +118EE;WARANG CITI NUMBER FIFTY;No;0;L;;;;50;N;;;;; +118EF;WARANG CITI NUMBER SIXTY;No;0;L;;;;60;N;;;;; +118F0;WARANG CITI NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +118F1;WARANG CITI NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +118F2;WARANG CITI NUMBER NINETY;No;0;L;;;;90;N;;;;; +118FF;WARANG CITI OM;Lo;0;L;;;;;N;;;;; +11AC0;PAU CIN HAU LETTER PA;Lo;0;L;;;;;N;;;;; +11AC1;PAU CIN HAU LETTER KA;Lo;0;L;;;;;N;;;;; +11AC2;PAU CIN HAU LETTER LA;Lo;0;L;;;;;N;;;;; +11AC3;PAU CIN HAU LETTER MA;Lo;0;L;;;;;N;;;;; +11AC4;PAU CIN HAU LETTER DA;Lo;0;L;;;;;N;;;;; +11AC5;PAU CIN HAU LETTER ZA;Lo;0;L;;;;;N;;;;; +11AC6;PAU CIN HAU LETTER VA;Lo;0;L;;;;;N;;;;; +11AC7;PAU CIN HAU LETTER NGA;Lo;0;L;;;;;N;;;;; +11AC8;PAU CIN HAU LETTER HA;Lo;0;L;;;;;N;;;;; +11AC9;PAU CIN HAU LETTER GA;Lo;0;L;;;;;N;;;;; +11ACA;PAU CIN HAU LETTER KHA;Lo;0;L;;;;;N;;;;; +11ACB;PAU CIN HAU LETTER SA;Lo;0;L;;;;;N;;;;; +11ACC;PAU CIN HAU LETTER BA;Lo;0;L;;;;;N;;;;; +11ACD;PAU CIN HAU LETTER CA;Lo;0;L;;;;;N;;;;; +11ACE;PAU CIN HAU LETTER TA;Lo;0;L;;;;;N;;;;; +11ACF;PAU CIN HAU LETTER THA;Lo;0;L;;;;;N;;;;; +11AD0;PAU CIN HAU LETTER NA;Lo;0;L;;;;;N;;;;; +11AD1;PAU CIN HAU LETTER PHA;Lo;0;L;;;;;N;;;;; +11AD2;PAU CIN HAU LETTER RA;Lo;0;L;;;;;N;;;;; +11AD3;PAU CIN HAU LETTER FA;Lo;0;L;;;;;N;;;;; +11AD4;PAU CIN HAU LETTER CHA;Lo;0;L;;;;;N;;;;; +11AD5;PAU CIN HAU LETTER A;Lo;0;L;;;;;N;;;;; +11AD6;PAU CIN HAU LETTER E;Lo;0;L;;;;;N;;;;; +11AD7;PAU CIN HAU LETTER I;Lo;0;L;;;;;N;;;;; +11AD8;PAU CIN HAU LETTER O;Lo;0;L;;;;;N;;;;; +11AD9;PAU CIN HAU LETTER U;Lo;0;L;;;;;N;;;;; +11ADA;PAU CIN HAU LETTER UA;Lo;0;L;;;;;N;;;;; +11ADB;PAU CIN HAU LETTER IA;Lo;0;L;;;;;N;;;;; +11ADC;PAU CIN HAU LETTER FINAL P;Lo;0;L;;;;;N;;;;; +11ADD;PAU CIN HAU LETTER FINAL K;Lo;0;L;;;;;N;;;;; +11ADE;PAU CIN HAU LETTER FINAL T;Lo;0;L;;;;;N;;;;; +11ADF;PAU CIN HAU LETTER FINAL M;Lo;0;L;;;;;N;;;;; +11AE0;PAU CIN HAU LETTER FINAL N;Lo;0;L;;;;;N;;;;; +11AE1;PAU CIN HAU LETTER FINAL L;Lo;0;L;;;;;N;;;;; +11AE2;PAU CIN HAU LETTER FINAL W;Lo;0;L;;;;;N;;;;; +11AE3;PAU CIN HAU LETTER FINAL NG;Lo;0;L;;;;;N;;;;; +11AE4;PAU CIN HAU LETTER FINAL Y;Lo;0;L;;;;;N;;;;; +11AE5;PAU CIN HAU RISING TONE LONG;Lo;0;L;;;;;N;;;;; +11AE6;PAU CIN HAU RISING TONE;Lo;0;L;;;;;N;;;;; +11AE7;PAU CIN HAU SANDHI GLOTTAL STOP;Lo;0;L;;;;;N;;;;; +11AE8;PAU CIN HAU RISING TONE LONG FINAL;Lo;0;L;;;;;N;;;;; +11AE9;PAU CIN HAU RISING TONE FINAL;Lo;0;L;;;;;N;;;;; +11AEA;PAU CIN HAU SANDHI GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;; +11AEB;PAU CIN HAU SANDHI TONE LONG;Lo;0;L;;;;;N;;;;; +11AEC;PAU CIN HAU SANDHI TONE;Lo;0;L;;;;;N;;;;; +11AED;PAU CIN HAU SANDHI TONE LONG FINAL;Lo;0;L;;;;;N;;;;; +11AEE;PAU CIN HAU SANDHI TONE FINAL;Lo;0;L;;;;;N;;;;; +11AEF;PAU CIN HAU MID-LEVEL TONE;Lo;0;L;;;;;N;;;;; +11AF0;PAU CIN HAU GLOTTAL STOP VARIANT;Lo;0;L;;;;;N;;;;; +11AF1;PAU CIN HAU MID-LEVEL TONE LONG FINAL;Lo;0;L;;;;;N;;;;; +11AF2;PAU CIN HAU MID-LEVEL TONE FINAL;Lo;0;L;;;;;N;;;;; +11AF3;PAU CIN HAU LOW-FALLING TONE LONG;Lo;0;L;;;;;N;;;;; +11AF4;PAU CIN HAU LOW-FALLING TONE;Lo;0;L;;;;;N;;;;; +11AF5;PAU CIN HAU GLOTTAL STOP;Lo;0;L;;;;;N;;;;; +11AF6;PAU CIN HAU LOW-FALLING TONE LONG FINAL;Lo;0;L;;;;;N;;;;; +11AF7;PAU CIN HAU LOW-FALLING TONE FINAL;Lo;0;L;;;;;N;;;;; +11AF8;PAU CIN HAU GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;; 12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;; 12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;; 12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;; @@ -18654,6 +20328,48 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1236C;CUNEIFORM SIGN ZU5 TIMES A;Lo;0;L;;;;;N;;;;; 1236D;CUNEIFORM SIGN ZUBUR;Lo;0;L;;;;;N;;;;; 1236E;CUNEIFORM SIGN ZUM;Lo;0;L;;;;;N;;;;; +1236F;CUNEIFORM SIGN KAP ELAMITE;Lo;0;L;;;;;N;;;;; +12370;CUNEIFORM SIGN AB TIMES NUN;Lo;0;L;;;;;N;;;;; +12371;CUNEIFORM SIGN AB2 TIMES A;Lo;0;L;;;;;N;;;;; +12372;CUNEIFORM SIGN AMAR TIMES KUG;Lo;0;L;;;;;N;;;;; +12373;CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS MASH;Lo;0;L;;;;;N;;;;; +12374;CUNEIFORM SIGN DAG3;Lo;0;L;;;;;N;;;;; +12375;CUNEIFORM SIGN DISH PLUS SHU;Lo;0;L;;;;;N;;;;; +12376;CUNEIFORM SIGN DUB TIMES SHE;Lo;0;L;;;;;N;;;;; +12377;CUNEIFORM SIGN EZEN TIMES GUD;Lo;0;L;;;;;N;;;;; +12378;CUNEIFORM SIGN EZEN TIMES SHE;Lo;0;L;;;;;N;;;;; +12379;CUNEIFORM SIGN GA2 TIMES AN PLUS KAK PLUS A;Lo;0;L;;;;;N;;;;; +1237A;CUNEIFORM SIGN GA2 TIMES ASH2;Lo;0;L;;;;;N;;;;; +1237B;CUNEIFORM SIGN GE22;Lo;0;L;;;;;N;;;;; +1237C;CUNEIFORM SIGN GIG;Lo;0;L;;;;;N;;;;; +1237D;CUNEIFORM SIGN HUSH;Lo;0;L;;;;;N;;;;; +1237E;CUNEIFORM SIGN KA TIMES ANSHE;Lo;0;L;;;;;N;;;;; +1237F;CUNEIFORM SIGN KA TIMES ASH3;Lo;0;L;;;;;N;;;;; +12380;CUNEIFORM SIGN KA TIMES GISH;Lo;0;L;;;;;N;;;;; +12381;CUNEIFORM SIGN KA TIMES GUD;Lo;0;L;;;;;N;;;;; +12382;CUNEIFORM SIGN KA TIMES HI TIMES ASH2;Lo;0;L;;;;;N;;;;; +12383;CUNEIFORM SIGN KA TIMES LUM;Lo;0;L;;;;;N;;;;; +12384;CUNEIFORM SIGN KA TIMES PA;Lo;0;L;;;;;N;;;;; +12385;CUNEIFORM SIGN KA TIMES SHUL;Lo;0;L;;;;;N;;;;; +12386;CUNEIFORM SIGN KA TIMES TU;Lo;0;L;;;;;N;;;;; +12387;CUNEIFORM SIGN KA TIMES UR2;Lo;0;L;;;;;N;;;;; +12388;CUNEIFORM SIGN LAGAB TIMES GI;Lo;0;L;;;;;N;;;;; +12389;CUNEIFORM SIGN LU2 SHESHIG TIMES BAD;Lo;0;L;;;;;N;;;;; +1238A;CUNEIFORM SIGN LU2 TIMES ESH2 PLUS LAL;Lo;0;L;;;;;N;;;;; +1238B;CUNEIFORM SIGN LU2 TIMES SHU;Lo;0;L;;;;;N;;;;; +1238C;CUNEIFORM SIGN MESH;Lo;0;L;;;;;N;;;;; +1238D;CUNEIFORM SIGN MUSH3 TIMES ZA;Lo;0;L;;;;;N;;;;; +1238E;CUNEIFORM SIGN NA4;Lo;0;L;;;;;N;;;;; +1238F;CUNEIFORM SIGN NIN;Lo;0;L;;;;;N;;;;; +12390;CUNEIFORM SIGN NIN9;Lo;0;L;;;;;N;;;;; +12391;CUNEIFORM SIGN NINDA2 TIMES BAL;Lo;0;L;;;;;N;;;;; +12392;CUNEIFORM SIGN NINDA2 TIMES GI;Lo;0;L;;;;;N;;;;; +12393;CUNEIFORM SIGN NU11 ROTATED NINETY DEGREES;Lo;0;L;;;;;N;;;;; +12394;CUNEIFORM SIGN PESH2 ASTERISK;Lo;0;L;;;;;N;;;;; +12395;CUNEIFORM SIGN PIR2;Lo;0;L;;;;;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;;;;; 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;;;;; @@ -18740,8 +20456,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 12453;CUNEIFORM NUMERIC SIGN FOUR BAN2 VARIANT FORM;Nl;0;L;;;;4;N;;;;; 12454;CUNEIFORM NUMERIC SIGN FIVE BAN2;Nl;0;L;;;;5;N;;;;; 12455;CUNEIFORM NUMERIC SIGN FIVE BAN2 VARIANT FORM;Nl;0;L;;;;5;N;;;;; -12456;CUNEIFORM NUMERIC SIGN NIGIDAMIN;Nl;0;L;;;;-1;N;;;;; -12457;CUNEIFORM NUMERIC SIGN NIGIDAESH;Nl;0;L;;;;-1;N;;;;; +12456;CUNEIFORM NUMERIC SIGN NIGIDAMIN;Nl;0;L;;;;2;N;;;;; +12457;CUNEIFORM NUMERIC SIGN NIGIDAESH;Nl;0;L;;;;3;N;;;;; 12458;CUNEIFORM NUMERIC SIGN ONE ESHE3;Nl;0;L;;;;1;N;;;;; 12459;CUNEIFORM NUMERIC SIGN TWO ESHE3;Nl;0;L;;;;2;N;;;;; 1245A;CUNEIFORM NUMERIC SIGN ONE THIRD DISH;Nl;0;L;;;;1/3;N;;;;; @@ -18753,10 +20469,23 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 12460;CUNEIFORM NUMERIC SIGN ONE QUARTER ASH;Nl;0;L;;;;1/4;N;;;;; 12461;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE SIXTH;Nl;0;L;;;;1/6;N;;;;; 12462;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER;Nl;0;L;;;;1/4;N;;;;; +12463;CUNEIFORM NUMERIC SIGN ONE QUARTER GUR;Nl;0;L;;;;1/4;N;;;;; +12464;CUNEIFORM NUMERIC SIGN ONE HALF GUR;Nl;0;L;;;;1/2;N;;;;; +12465;CUNEIFORM NUMERIC SIGN ELAMITE ONE THIRD;Nl;0;L;;;;1/3;N;;;;; +12466;CUNEIFORM NUMERIC SIGN ELAMITE TWO THIRDS;Nl;0;L;;;;2/3;N;;;;; +12467;CUNEIFORM NUMERIC SIGN ELAMITE FORTY;Nl;0;L;;;;40;N;;;;; +12468;CUNEIFORM NUMERIC SIGN ELAMITE FIFTY;Nl;0;L;;;;50;N;;;;; +12469;CUNEIFORM NUMERIC SIGN FOUR U VARIANT FORM;Nl;0;L;;;;4;N;;;;; +1246A;CUNEIFORM NUMERIC SIGN FIVE U VARIANT FORM;Nl;0;L;;;;5;N;;;;; +1246B;CUNEIFORM NUMERIC SIGN SIX U VARIANT FORM;Nl;0;L;;;;6;N;;;;; +1246C;CUNEIFORM NUMERIC SIGN SEVEN U VARIANT FORM;Nl;0;L;;;;7;N;;;;; +1246D;CUNEIFORM NUMERIC SIGN EIGHT U VARIANT FORM;Nl;0;L;;;;8;N;;;;; +1246E;CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM;Nl;0;L;;;;9;N;;;;; 12470;CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER;Po;0;L;;;;;N;;;;; 12471;CUNEIFORM PUNCTUATION SIGN VERTICAL COLON;Po;0;L;;;;;N;;;;; 12472;CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON;Po;0;L;;;;;N;;;;; 12473;CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON;Po;0;L;;;;;N;;;;; +12474;CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON;Po;0;L;;;;;N;;;;; 13000;EGYPTIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;; 13001;EGYPTIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;; 13002;EGYPTIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;; @@ -20397,6 +22126,212 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 16A36;BAMUM LETTER PHASE-F KPA;Lo;0;L;;;;;N;;;;; 16A37;BAMUM LETTER PHASE-F SAMBA;Lo;0;L;;;;;N;;;;; 16A38;BAMUM LETTER PHASE-F VUEQ;Lo;0;L;;;;;N;;;;; +16A40;MRO LETTER TA;Lo;0;L;;;;;N;;;;; +16A41;MRO LETTER NGI;Lo;0;L;;;;;N;;;;; +16A42;MRO LETTER YO;Lo;0;L;;;;;N;;;;; +16A43;MRO LETTER MIM;Lo;0;L;;;;;N;;;;; +16A44;MRO LETTER BA;Lo;0;L;;;;;N;;;;; +16A45;MRO LETTER DA;Lo;0;L;;;;;N;;;;; +16A46;MRO LETTER A;Lo;0;L;;;;;N;;;;; +16A47;MRO LETTER PHI;Lo;0;L;;;;;N;;;;; +16A48;MRO LETTER KHAI;Lo;0;L;;;;;N;;;;; +16A49;MRO LETTER HAO;Lo;0;L;;;;;N;;;;; +16A4A;MRO LETTER DAI;Lo;0;L;;;;;N;;;;; +16A4B;MRO LETTER CHU;Lo;0;L;;;;;N;;;;; +16A4C;MRO LETTER KEAAE;Lo;0;L;;;;;N;;;;; +16A4D;MRO LETTER OL;Lo;0;L;;;;;N;;;;; +16A4E;MRO LETTER MAEM;Lo;0;L;;;;;N;;;;; +16A4F;MRO LETTER NIN;Lo;0;L;;;;;N;;;;; +16A50;MRO LETTER PA;Lo;0;L;;;;;N;;;;; +16A51;MRO LETTER OO;Lo;0;L;;;;;N;;;;; +16A52;MRO LETTER O;Lo;0;L;;;;;N;;;;; +16A53;MRO LETTER RO;Lo;0;L;;;;;N;;;;; +16A54;MRO LETTER SHI;Lo;0;L;;;;;N;;;;; +16A55;MRO LETTER THEA;Lo;0;L;;;;;N;;;;; +16A56;MRO LETTER EA;Lo;0;L;;;;;N;;;;; +16A57;MRO LETTER WA;Lo;0;L;;;;;N;;;;; +16A58;MRO LETTER E;Lo;0;L;;;;;N;;;;; +16A59;MRO LETTER KO;Lo;0;L;;;;;N;;;;; +16A5A;MRO LETTER LAN;Lo;0;L;;;;;N;;;;; +16A5B;MRO LETTER LA;Lo;0;L;;;;;N;;;;; +16A5C;MRO LETTER HAI;Lo;0;L;;;;;N;;;;; +16A5D;MRO LETTER RI;Lo;0;L;;;;;N;;;;; +16A5E;MRO LETTER TEK;Lo;0;L;;;;;N;;;;; +16A60;MRO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +16A61;MRO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +16A62;MRO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +16A63;MRO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +16A64;MRO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +16A65;MRO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +16A66;MRO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +16A67;MRO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +16A68;MRO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +16A69;MRO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +16A6E;MRO DANDA;Po;0;L;;;;;N;;;;; +16A6F;MRO DOUBLE DANDA;Po;0;L;;;;;N;;;;; +16AD0;BASSA VAH LETTER ENNI;Lo;0;L;;;;;N;;;;; +16AD1;BASSA VAH LETTER KA;Lo;0;L;;;;;N;;;;; +16AD2;BASSA VAH LETTER SE;Lo;0;L;;;;;N;;;;; +16AD3;BASSA VAH LETTER FA;Lo;0;L;;;;;N;;;;; +16AD4;BASSA VAH LETTER MBE;Lo;0;L;;;;;N;;;;; +16AD5;BASSA VAH LETTER YIE;Lo;0;L;;;;;N;;;;; +16AD6;BASSA VAH LETTER GAH;Lo;0;L;;;;;N;;;;; +16AD7;BASSA VAH LETTER DHII;Lo;0;L;;;;;N;;;;; +16AD8;BASSA VAH LETTER KPAH;Lo;0;L;;;;;N;;;;; +16AD9;BASSA VAH LETTER JO;Lo;0;L;;;;;N;;;;; +16ADA;BASSA VAH LETTER HWAH;Lo;0;L;;;;;N;;;;; +16ADB;BASSA VAH LETTER WA;Lo;0;L;;;;;N;;;;; +16ADC;BASSA VAH LETTER ZO;Lo;0;L;;;;;N;;;;; +16ADD;BASSA VAH LETTER GBU;Lo;0;L;;;;;N;;;;; +16ADE;BASSA VAH LETTER DO;Lo;0;L;;;;;N;;;;; +16ADF;BASSA VAH LETTER CE;Lo;0;L;;;;;N;;;;; +16AE0;BASSA VAH LETTER UWU;Lo;0;L;;;;;N;;;;; +16AE1;BASSA VAH LETTER TO;Lo;0;L;;;;;N;;;;; +16AE2;BASSA VAH LETTER BA;Lo;0;L;;;;;N;;;;; +16AE3;BASSA VAH LETTER VU;Lo;0;L;;;;;N;;;;; +16AE4;BASSA VAH LETTER YEIN;Lo;0;L;;;;;N;;;;; +16AE5;BASSA VAH LETTER PA;Lo;0;L;;;;;N;;;;; +16AE6;BASSA VAH LETTER WADDA;Lo;0;L;;;;;N;;;;; +16AE7;BASSA VAH LETTER A;Lo;0;L;;;;;N;;;;; +16AE8;BASSA VAH LETTER O;Lo;0;L;;;;;N;;;;; +16AE9;BASSA VAH LETTER OO;Lo;0;L;;;;;N;;;;; +16AEA;BASSA VAH LETTER U;Lo;0;L;;;;;N;;;;; +16AEB;BASSA VAH LETTER EE;Lo;0;L;;;;;N;;;;; +16AEC;BASSA VAH LETTER E;Lo;0;L;;;;;N;;;;; +16AED;BASSA VAH LETTER I;Lo;0;L;;;;;N;;;;; +16AF0;BASSA VAH COMBINING HIGH TONE;Mn;1;NSM;;;;;N;;;;; +16AF1;BASSA VAH COMBINING LOW TONE;Mn;1;NSM;;;;;N;;;;; +16AF2;BASSA VAH COMBINING MID TONE;Mn;1;NSM;;;;;N;;;;; +16AF3;BASSA VAH COMBINING LOW-MID TONE;Mn;1;NSM;;;;;N;;;;; +16AF4;BASSA VAH COMBINING HIGH-LOW TONE;Mn;1;NSM;;;;;N;;;;; +16AF5;BASSA VAH FULL STOP;Po;0;L;;;;;N;;;;; +16B00;PAHAWH HMONG VOWEL KEEB;Lo;0;L;;;;;N;;;;; +16B01;PAHAWH HMONG VOWEL KEEV;Lo;0;L;;;;;N;;;;; +16B02;PAHAWH HMONG VOWEL KIB;Lo;0;L;;;;;N;;;;; +16B03;PAHAWH HMONG VOWEL KIV;Lo;0;L;;;;;N;;;;; +16B04;PAHAWH HMONG VOWEL KAUB;Lo;0;L;;;;;N;;;;; +16B05;PAHAWH HMONG VOWEL KAUV;Lo;0;L;;;;;N;;;;; +16B06;PAHAWH HMONG VOWEL KUB;Lo;0;L;;;;;N;;;;; +16B07;PAHAWH HMONG VOWEL KUV;Lo;0;L;;;;;N;;;;; +16B08;PAHAWH HMONG VOWEL KEB;Lo;0;L;;;;;N;;;;; +16B09;PAHAWH HMONG VOWEL KEV;Lo;0;L;;;;;N;;;;; +16B0A;PAHAWH HMONG VOWEL KAIB;Lo;0;L;;;;;N;;;;; +16B0B;PAHAWH HMONG VOWEL KAIV;Lo;0;L;;;;;N;;;;; +16B0C;PAHAWH HMONG VOWEL KOOB;Lo;0;L;;;;;N;;;;; +16B0D;PAHAWH HMONG VOWEL KOOV;Lo;0;L;;;;;N;;;;; +16B0E;PAHAWH HMONG VOWEL KAWB;Lo;0;L;;;;;N;;;;; +16B0F;PAHAWH HMONG VOWEL KAWV;Lo;0;L;;;;;N;;;;; +16B10;PAHAWH HMONG VOWEL KUAB;Lo;0;L;;;;;N;;;;; +16B11;PAHAWH HMONG VOWEL KUAV;Lo;0;L;;;;;N;;;;; +16B12;PAHAWH HMONG VOWEL KOB;Lo;0;L;;;;;N;;;;; +16B13;PAHAWH HMONG VOWEL KOV;Lo;0;L;;;;;N;;;;; +16B14;PAHAWH HMONG VOWEL KIAB;Lo;0;L;;;;;N;;;;; +16B15;PAHAWH HMONG VOWEL KIAV;Lo;0;L;;;;;N;;;;; +16B16;PAHAWH HMONG VOWEL KAB;Lo;0;L;;;;;N;;;;; +16B17;PAHAWH HMONG VOWEL KAV;Lo;0;L;;;;;N;;;;; +16B18;PAHAWH HMONG VOWEL KWB;Lo;0;L;;;;;N;;;;; +16B19;PAHAWH HMONG VOWEL KWV;Lo;0;L;;;;;N;;;;; +16B1A;PAHAWH HMONG VOWEL KAAB;Lo;0;L;;;;;N;;;;; +16B1B;PAHAWH HMONG VOWEL KAAV;Lo;0;L;;;;;N;;;;; +16B1C;PAHAWH HMONG CONSONANT VAU;Lo;0;L;;;;;N;;;;; +16B1D;PAHAWH HMONG CONSONANT NTSAU;Lo;0;L;;;;;N;;;;; +16B1E;PAHAWH HMONG CONSONANT LAU;Lo;0;L;;;;;N;;;;; +16B1F;PAHAWH HMONG CONSONANT HAU;Lo;0;L;;;;;N;;;;; +16B20;PAHAWH HMONG CONSONANT NLAU;Lo;0;L;;;;;N;;;;; +16B21;PAHAWH HMONG CONSONANT RAU;Lo;0;L;;;;;N;;;;; +16B22;PAHAWH HMONG CONSONANT NKAU;Lo;0;L;;;;;N;;;;; +16B23;PAHAWH HMONG CONSONANT QHAU;Lo;0;L;;;;;N;;;;; +16B24;PAHAWH HMONG CONSONANT YAU;Lo;0;L;;;;;N;;;;; +16B25;PAHAWH HMONG CONSONANT HLAU;Lo;0;L;;;;;N;;;;; +16B26;PAHAWH HMONG CONSONANT MAU;Lo;0;L;;;;;N;;;;; +16B27;PAHAWH HMONG CONSONANT CHAU;Lo;0;L;;;;;N;;;;; +16B28;PAHAWH HMONG CONSONANT NCHAU;Lo;0;L;;;;;N;;;;; +16B29;PAHAWH HMONG CONSONANT HNAU;Lo;0;L;;;;;N;;;;; +16B2A;PAHAWH HMONG CONSONANT PLHAU;Lo;0;L;;;;;N;;;;; +16B2B;PAHAWH HMONG CONSONANT NTHAU;Lo;0;L;;;;;N;;;;; +16B2C;PAHAWH HMONG CONSONANT NAU;Lo;0;L;;;;;N;;;;; +16B2D;PAHAWH HMONG CONSONANT AU;Lo;0;L;;;;;N;;;;; +16B2E;PAHAWH HMONG CONSONANT XAU;Lo;0;L;;;;;N;;;;; +16B2F;PAHAWH HMONG CONSONANT CAU;Lo;0;L;;;;;N;;;;; +16B30;PAHAWH HMONG MARK CIM TUB;Mn;230;NSM;;;;;N;;;;; +16B31;PAHAWH HMONG MARK CIM SO;Mn;230;NSM;;;;;N;;;;; +16B32;PAHAWH HMONG MARK CIM KES;Mn;230;NSM;;;;;N;;;;; +16B33;PAHAWH HMONG MARK CIM KHAV;Mn;230;NSM;;;;;N;;;;; +16B34;PAHAWH HMONG MARK CIM SUAM;Mn;230;NSM;;;;;N;;;;; +16B35;PAHAWH HMONG MARK CIM HOM;Mn;230;NSM;;;;;N;;;;; +16B36;PAHAWH HMONG MARK CIM TAUM;Mn;230;NSM;;;;;N;;;;; +16B37;PAHAWH HMONG SIGN VOS THOM;Po;0;L;;;;;N;;;;; +16B38;PAHAWH HMONG SIGN VOS TSHAB CEEB;Po;0;L;;;;;N;;;;; +16B39;PAHAWH HMONG SIGN CIM CHEEM;Po;0;L;;;;;N;;;;; +16B3A;PAHAWH HMONG SIGN VOS THIAB;Po;0;L;;;;;N;;;;; +16B3B;PAHAWH HMONG SIGN VOS FEEM;Po;0;L;;;;;N;;;;; +16B3C;PAHAWH HMONG SIGN XYEEM NTXIV;So;0;L;;;;;N;;;;; +16B3D;PAHAWH HMONG SIGN XYEEM RHO;So;0;L;;;;;N;;;;; +16B3E;PAHAWH HMONG SIGN XYEEM TOV;So;0;L;;;;;N;;;;; +16B3F;PAHAWH HMONG SIGN XYEEM FAIB;So;0;L;;;;;N;;;;; +16B40;PAHAWH HMONG SIGN VOS SEEV;Lm;0;L;;;;;N;;;;; +16B41;PAHAWH HMONG SIGN MEEJ SUAB;Lm;0;L;;;;;N;;;;; +16B42;PAHAWH HMONG SIGN VOS NRUA;Lm;0;L;;;;;N;;;;; +16B43;PAHAWH HMONG SIGN IB YAM;Lm;0;L;;;;;N;;;;; +16B44;PAHAWH HMONG SIGN XAUS;Po;0;L;;;;;N;;;;; +16B45;PAHAWH HMONG SIGN CIM TSOV ROG;So;0;L;;;;;N;;;;; +16B50;PAHAWH HMONG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +16B51;PAHAWH HMONG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +16B52;PAHAWH HMONG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +16B53;PAHAWH HMONG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +16B54;PAHAWH HMONG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +16B55;PAHAWH HMONG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +16B56;PAHAWH HMONG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +16B57;PAHAWH HMONG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +16B58;PAHAWH HMONG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +16B59;PAHAWH HMONG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +16B5B;PAHAWH HMONG NUMBER TENS;No;0;L;;;;10;N;;;;; +16B5C;PAHAWH HMONG NUMBER HUNDREDS;No;0;L;;;;100;N;;;;; +16B5D;PAHAWH HMONG NUMBER TEN THOUSANDS;No;0;L;;;;10000;N;;;;; +16B5E;PAHAWH HMONG NUMBER MILLIONS;No;0;L;;;;1000000;N;;;;; +16B5F;PAHAWH HMONG NUMBER HUNDRED MILLIONS;No;0;L;;;;100000000;N;;;;; +16B60;PAHAWH HMONG NUMBER TEN BILLIONS;No;0;L;;;;10000000000;N;;;;; +16B61;PAHAWH HMONG NUMBER TRILLIONS;No;0;L;;;;1000000000000;N;;;;; +16B63;PAHAWH HMONG SIGN VOS LUB;Lo;0;L;;;;;N;;;;; +16B64;PAHAWH HMONG SIGN XYOO;Lo;0;L;;;;;N;;;;; +16B65;PAHAWH HMONG SIGN HLI;Lo;0;L;;;;;N;;;;; +16B66;PAHAWH HMONG SIGN THIRD-STAGE HLI;Lo;0;L;;;;;N;;;;; +16B67;PAHAWH HMONG SIGN ZWJ THAJ;Lo;0;L;;;;;N;;;;; +16B68;PAHAWH HMONG SIGN HNUB;Lo;0;L;;;;;N;;;;; +16B69;PAHAWH HMONG SIGN NQIG;Lo;0;L;;;;;N;;;;; +16B6A;PAHAWH HMONG SIGN XIAB;Lo;0;L;;;;;N;;;;; +16B6B;PAHAWH HMONG SIGN NTUJ;Lo;0;L;;;;;N;;;;; +16B6C;PAHAWH HMONG SIGN AV;Lo;0;L;;;;;N;;;;; +16B6D;PAHAWH HMONG SIGN TXHEEJ CEEV;Lo;0;L;;;;;N;;;;; +16B6E;PAHAWH HMONG SIGN MEEJ TSEEB;Lo;0;L;;;;;N;;;;; +16B6F;PAHAWH HMONG SIGN TAU;Lo;0;L;;;;;N;;;;; +16B70;PAHAWH HMONG SIGN LOS;Lo;0;L;;;;;N;;;;; +16B71;PAHAWH HMONG SIGN MUS;Lo;0;L;;;;;N;;;;; +16B72;PAHAWH HMONG SIGN CIM HAIS LUS NTOG NTOG;Lo;0;L;;;;;N;;;;; +16B73;PAHAWH HMONG SIGN CIM CUAM TSHOOJ;Lo;0;L;;;;;N;;;;; +16B74;PAHAWH HMONG SIGN CIM TXWV;Lo;0;L;;;;;N;;;;; +16B75;PAHAWH HMONG SIGN CIM TXWV CHWV;Lo;0;L;;;;;N;;;;; +16B76;PAHAWH HMONG SIGN CIM PUB DAWB;Lo;0;L;;;;;N;;;;; +16B77;PAHAWH HMONG SIGN CIM NRES TOS;Lo;0;L;;;;;N;;;;; +16B7D;PAHAWH HMONG CLAN SIGN TSHEEJ;Lo;0;L;;;;;N;;;;; +16B7E;PAHAWH HMONG CLAN SIGN YEEG;Lo;0;L;;;;;N;;;;; +16B7F;PAHAWH HMONG CLAN SIGN LIS;Lo;0;L;;;;;N;;;;; +16B80;PAHAWH HMONG CLAN SIGN LAUJ;Lo;0;L;;;;;N;;;;; +16B81;PAHAWH HMONG CLAN SIGN XYOOJ;Lo;0;L;;;;;N;;;;; +16B82;PAHAWH HMONG CLAN SIGN KOO;Lo;0;L;;;;;N;;;;; +16B83;PAHAWH HMONG CLAN SIGN HAWJ;Lo;0;L;;;;;N;;;;; +16B84;PAHAWH HMONG CLAN SIGN MUAS;Lo;0;L;;;;;N;;;;; +16B85;PAHAWH HMONG CLAN SIGN THOJ;Lo;0;L;;;;;N;;;;; +16B86;PAHAWH HMONG CLAN SIGN TSAB;Lo;0;L;;;;;N;;;;; +16B87;PAHAWH HMONG CLAN SIGN PHAB;Lo;0;L;;;;;N;;;;; +16B88;PAHAWH HMONG CLAN SIGN KHAB;Lo;0;L;;;;;N;;;;; +16B89;PAHAWH HMONG CLAN SIGN HAM;Lo;0;L;;;;;N;;;;; +16B8A;PAHAWH HMONG CLAN SIGN VAJ;Lo;0;L;;;;;N;;;;; +16B8B;PAHAWH HMONG CLAN SIGN FAJ;Lo;0;L;;;;;N;;;;; +16B8C;PAHAWH HMONG CLAN SIGN YAJ;Lo;0;L;;;;;N;;;;; +16B8D;PAHAWH HMONG CLAN SIGN TSWB;Lo;0;L;;;;;N;;;;; +16B8E;PAHAWH HMONG CLAN SIGN KWM;Lo;0;L;;;;;N;;;;; +16B8F;PAHAWH HMONG CLAN SIGN VWJ;Lo;0;L;;;;;N;;;;; 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;;;;; @@ -20532,6 +22467,153 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 16F9F;MIAO LETTER REFORMED TONE-8;Lm;0;L;;;;;N;;;;; 1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;; 1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;; +1BC00;DUPLOYAN LETTER H;Lo;0;L;;;;;N;;;;; +1BC01;DUPLOYAN LETTER X;Lo;0;L;;;;;N;;;;; +1BC02;DUPLOYAN LETTER P;Lo;0;L;;;;;N;;;;; +1BC03;DUPLOYAN LETTER T;Lo;0;L;;;;;N;;;;; +1BC04;DUPLOYAN LETTER F;Lo;0;L;;;;;N;;;;; +1BC05;DUPLOYAN LETTER K;Lo;0;L;;;;;N;;;;; +1BC06;DUPLOYAN LETTER L;Lo;0;L;;;;;N;;;;; +1BC07;DUPLOYAN LETTER B;Lo;0;L;;;;;N;;;;; +1BC08;DUPLOYAN LETTER D;Lo;0;L;;;;;N;;;;; +1BC09;DUPLOYAN LETTER V;Lo;0;L;;;;;N;;;;; +1BC0A;DUPLOYAN LETTER G;Lo;0;L;;;;;N;;;;; +1BC0B;DUPLOYAN LETTER R;Lo;0;L;;;;;N;;;;; +1BC0C;DUPLOYAN LETTER P N;Lo;0;L;;;;;N;;;;; +1BC0D;DUPLOYAN LETTER D S;Lo;0;L;;;;;N;;;;; +1BC0E;DUPLOYAN LETTER F N;Lo;0;L;;;;;N;;;;; +1BC0F;DUPLOYAN LETTER K M;Lo;0;L;;;;;N;;;;; +1BC10;DUPLOYAN LETTER R S;Lo;0;L;;;;;N;;;;; +1BC11;DUPLOYAN LETTER TH;Lo;0;L;;;;;N;;;;; +1BC12;DUPLOYAN LETTER SLOAN DH;Lo;0;L;;;;;N;;;;; +1BC13;DUPLOYAN LETTER DH;Lo;0;L;;;;;N;;;;; +1BC14;DUPLOYAN LETTER KK;Lo;0;L;;;;;N;;;;; +1BC15;DUPLOYAN LETTER SLOAN J;Lo;0;L;;;;;N;;;;; +1BC16;DUPLOYAN LETTER HL;Lo;0;L;;;;;N;;;;; +1BC17;DUPLOYAN LETTER LH;Lo;0;L;;;;;N;;;;; +1BC18;DUPLOYAN LETTER RH;Lo;0;L;;;;;N;;;;; +1BC19;DUPLOYAN LETTER M;Lo;0;L;;;;;N;;;;; +1BC1A;DUPLOYAN LETTER N;Lo;0;L;;;;;N;;;;; +1BC1B;DUPLOYAN LETTER J;Lo;0;L;;;;;N;;;;; +1BC1C;DUPLOYAN LETTER S;Lo;0;L;;;;;N;;;;; +1BC1D;DUPLOYAN LETTER M N;Lo;0;L;;;;;N;;;;; +1BC1E;DUPLOYAN LETTER N M;Lo;0;L;;;;;N;;;;; +1BC1F;DUPLOYAN LETTER J M;Lo;0;L;;;;;N;;;;; +1BC20;DUPLOYAN LETTER S J;Lo;0;L;;;;;N;;;;; +1BC21;DUPLOYAN LETTER M WITH DOT;Lo;0;L;;;;;N;;;;; +1BC22;DUPLOYAN LETTER N WITH DOT;Lo;0;L;;;;;N;;;;; +1BC23;DUPLOYAN LETTER J WITH DOT;Lo;0;L;;;;;N;;;;; +1BC24;DUPLOYAN LETTER J WITH DOTS INSIDE AND ABOVE;Lo;0;L;;;;;N;;;;; +1BC25;DUPLOYAN LETTER S WITH DOT;Lo;0;L;;;;;N;;;;; +1BC26;DUPLOYAN LETTER S WITH DOT BELOW;Lo;0;L;;;;;N;;;;; +1BC27;DUPLOYAN LETTER M S;Lo;0;L;;;;;N;;;;; +1BC28;DUPLOYAN LETTER N S;Lo;0;L;;;;;N;;;;; +1BC29;DUPLOYAN LETTER J S;Lo;0;L;;;;;N;;;;; +1BC2A;DUPLOYAN LETTER S S;Lo;0;L;;;;;N;;;;; +1BC2B;DUPLOYAN LETTER M N S;Lo;0;L;;;;;N;;;;; +1BC2C;DUPLOYAN LETTER N M S;Lo;0;L;;;;;N;;;;; +1BC2D;DUPLOYAN LETTER J M S;Lo;0;L;;;;;N;;;;; +1BC2E;DUPLOYAN LETTER S J S;Lo;0;L;;;;;N;;;;; +1BC2F;DUPLOYAN LETTER J S WITH DOT;Lo;0;L;;;;;N;;;;; +1BC30;DUPLOYAN LETTER J N;Lo;0;L;;;;;N;;;;; +1BC31;DUPLOYAN LETTER J N S;Lo;0;L;;;;;N;;;;; +1BC32;DUPLOYAN LETTER S T;Lo;0;L;;;;;N;;;;; +1BC33;DUPLOYAN LETTER S T R;Lo;0;L;;;;;N;;;;; +1BC34;DUPLOYAN LETTER S P;Lo;0;L;;;;;N;;;;; +1BC35;DUPLOYAN LETTER S P R;Lo;0;L;;;;;N;;;;; +1BC36;DUPLOYAN LETTER T S;Lo;0;L;;;;;N;;;;; +1BC37;DUPLOYAN LETTER T R S;Lo;0;L;;;;;N;;;;; +1BC38;DUPLOYAN LETTER W;Lo;0;L;;;;;N;;;;; +1BC39;DUPLOYAN LETTER WH;Lo;0;L;;;;;N;;;;; +1BC3A;DUPLOYAN LETTER W R;Lo;0;L;;;;;N;;;;; +1BC3B;DUPLOYAN LETTER S N;Lo;0;L;;;;;N;;;;; +1BC3C;DUPLOYAN LETTER S M;Lo;0;L;;;;;N;;;;; +1BC3D;DUPLOYAN LETTER K R S;Lo;0;L;;;;;N;;;;; +1BC3E;DUPLOYAN LETTER G R S;Lo;0;L;;;;;N;;;;; +1BC3F;DUPLOYAN LETTER S K;Lo;0;L;;;;;N;;;;; +1BC40;DUPLOYAN LETTER S K R;Lo;0;L;;;;;N;;;;; +1BC41;DUPLOYAN LETTER A;Lo;0;L;;;;;N;;;;; +1BC42;DUPLOYAN LETTER SLOAN OW;Lo;0;L;;;;;N;;;;; +1BC43;DUPLOYAN LETTER OA;Lo;0;L;;;;;N;;;;; +1BC44;DUPLOYAN LETTER O;Lo;0;L;;;;;N;;;;; +1BC45;DUPLOYAN LETTER AOU;Lo;0;L;;;;;N;;;;; +1BC46;DUPLOYAN LETTER I;Lo;0;L;;;;;N;;;;; +1BC47;DUPLOYAN LETTER E;Lo;0;L;;;;;N;;;;; +1BC48;DUPLOYAN LETTER IE;Lo;0;L;;;;;N;;;;; +1BC49;DUPLOYAN LETTER SHORT I;Lo;0;L;;;;;N;;;;; +1BC4A;DUPLOYAN LETTER UI;Lo;0;L;;;;;N;;;;; +1BC4B;DUPLOYAN LETTER EE;Lo;0;L;;;;;N;;;;; +1BC4C;DUPLOYAN LETTER SLOAN EH;Lo;0;L;;;;;N;;;;; +1BC4D;DUPLOYAN LETTER ROMANIAN I;Lo;0;L;;;;;N;;;;; +1BC4E;DUPLOYAN LETTER SLOAN EE;Lo;0;L;;;;;N;;;;; +1BC4F;DUPLOYAN LETTER LONG I;Lo;0;L;;;;;N;;;;; +1BC50;DUPLOYAN LETTER YE;Lo;0;L;;;;;N;;;;; +1BC51;DUPLOYAN LETTER U;Lo;0;L;;;;;N;;;;; +1BC52;DUPLOYAN LETTER EU;Lo;0;L;;;;;N;;;;; +1BC53;DUPLOYAN LETTER XW;Lo;0;L;;;;;N;;;;; +1BC54;DUPLOYAN LETTER U N;Lo;0;L;;;;;N;;;;; +1BC55;DUPLOYAN LETTER LONG U;Lo;0;L;;;;;N;;;;; +1BC56;DUPLOYAN LETTER ROMANIAN U;Lo;0;L;;;;;N;;;;; +1BC57;DUPLOYAN LETTER UH;Lo;0;L;;;;;N;;;;; +1BC58;DUPLOYAN LETTER SLOAN U;Lo;0;L;;;;;N;;;;; +1BC59;DUPLOYAN LETTER OOH;Lo;0;L;;;;;N;;;;; +1BC5A;DUPLOYAN LETTER OW;Lo;0;L;;;;;N;;;;; +1BC5B;DUPLOYAN LETTER OU;Lo;0;L;;;;;N;;;;; +1BC5C;DUPLOYAN LETTER WA;Lo;0;L;;;;;N;;;;; +1BC5D;DUPLOYAN LETTER WO;Lo;0;L;;;;;N;;;;; +1BC5E;DUPLOYAN LETTER WI;Lo;0;L;;;;;N;;;;; +1BC5F;DUPLOYAN LETTER WEI;Lo;0;L;;;;;N;;;;; +1BC60;DUPLOYAN LETTER WOW;Lo;0;L;;;;;N;;;;; +1BC61;DUPLOYAN LETTER NASAL U;Lo;0;L;;;;;N;;;;; +1BC62;DUPLOYAN LETTER NASAL O;Lo;0;L;;;;;N;;;;; +1BC63;DUPLOYAN LETTER NASAL I;Lo;0;L;;;;;N;;;;; +1BC64;DUPLOYAN LETTER NASAL A;Lo;0;L;;;;;N;;;;; +1BC65;DUPLOYAN LETTER PERNIN AN;Lo;0;L;;;;;N;;;;; +1BC66;DUPLOYAN LETTER PERNIN AM;Lo;0;L;;;;;N;;;;; +1BC67;DUPLOYAN LETTER SLOAN EN;Lo;0;L;;;;;N;;;;; +1BC68;DUPLOYAN LETTER SLOAN AN;Lo;0;L;;;;;N;;;;; +1BC69;DUPLOYAN LETTER SLOAN ON;Lo;0;L;;;;;N;;;;; +1BC6A;DUPLOYAN LETTER VOCALIC M;Lo;0;L;;;;;N;;;;; +1BC70;DUPLOYAN AFFIX LEFT HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;; +1BC71;DUPLOYAN AFFIX MID HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;; +1BC72;DUPLOYAN AFFIX RIGHT HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;; +1BC73;DUPLOYAN AFFIX LOW VERTICAL SECANT;Lo;0;L;;;;;N;;;;; +1BC74;DUPLOYAN AFFIX MID VERTICAL SECANT;Lo;0;L;;;;;N;;;;; +1BC75;DUPLOYAN AFFIX HIGH VERTICAL SECANT;Lo;0;L;;;;;N;;;;; +1BC76;DUPLOYAN AFFIX ATTACHED SECANT;Lo;0;L;;;;;N;;;;; +1BC77;DUPLOYAN AFFIX ATTACHED LEFT-TO-RIGHT SECANT;Lo;0;L;;;;;N;;;;; +1BC78;DUPLOYAN AFFIX ATTACHED TANGENT;Lo;0;L;;;;;N;;;;; +1BC79;DUPLOYAN AFFIX ATTACHED TAIL;Lo;0;L;;;;;N;;;;; +1BC7A;DUPLOYAN AFFIX ATTACHED E HOOK;Lo;0;L;;;;;N;;;;; +1BC7B;DUPLOYAN AFFIX ATTACHED I HOOK;Lo;0;L;;;;;N;;;;; +1BC7C;DUPLOYAN AFFIX ATTACHED TANGENT HOOK;Lo;0;L;;;;;N;;;;; +1BC80;DUPLOYAN AFFIX HIGH ACUTE;Lo;0;L;;;;;N;;;;; +1BC81;DUPLOYAN AFFIX HIGH TIGHT ACUTE;Lo;0;L;;;;;N;;;;; +1BC82;DUPLOYAN AFFIX HIGH GRAVE;Lo;0;L;;;;;N;;;;; +1BC83;DUPLOYAN AFFIX HIGH LONG GRAVE;Lo;0;L;;;;;N;;;;; +1BC84;DUPLOYAN AFFIX HIGH DOT;Lo;0;L;;;;;N;;;;; +1BC85;DUPLOYAN AFFIX HIGH CIRCLE;Lo;0;L;;;;;N;;;;; +1BC86;DUPLOYAN AFFIX HIGH LINE;Lo;0;L;;;;;N;;;;; +1BC87;DUPLOYAN AFFIX HIGH WAVE;Lo;0;L;;;;;N;;;;; +1BC88;DUPLOYAN AFFIX HIGH VERTICAL;Lo;0;L;;;;;N;;;;; +1BC90;DUPLOYAN AFFIX LOW ACUTE;Lo;0;L;;;;;N;;;;; +1BC91;DUPLOYAN AFFIX LOW TIGHT ACUTE;Lo;0;L;;;;;N;;;;; +1BC92;DUPLOYAN AFFIX LOW GRAVE;Lo;0;L;;;;;N;;;;; +1BC93;DUPLOYAN AFFIX LOW LONG GRAVE;Lo;0;L;;;;;N;;;;; +1BC94;DUPLOYAN AFFIX LOW DOT;Lo;0;L;;;;;N;;;;; +1BC95;DUPLOYAN AFFIX LOW CIRCLE;Lo;0;L;;;;;N;;;;; +1BC96;DUPLOYAN AFFIX LOW LINE;Lo;0;L;;;;;N;;;;; +1BC97;DUPLOYAN AFFIX LOW WAVE;Lo;0;L;;;;;N;;;;; +1BC98;DUPLOYAN AFFIX LOW VERTICAL;Lo;0;L;;;;;N;;;;; +1BC99;DUPLOYAN AFFIX LOW ARROW;Lo;0;L;;;;;N;;;;; +1BC9C;DUPLOYAN SIGN O WITH CROSS;So;0;L;;;;;N;;;;; +1BC9D;DUPLOYAN THICK LETTER SELECTOR;Mn;0;NSM;;;;;N;;;;; +1BC9E;DUPLOYAN DOUBLE MARK;Mn;1;NSM;;;;;N;;;;; +1BC9F;DUPLOYAN PUNCTUATION CHINOOK FULL STOP;Po;0;L;;;;;N;;;;; +1BCA0;SHORTHAND FORMAT LETTER OVERLAP;Cf;0;BN;;;;;N;;;;; +1BCA1;SHORTHAND FORMAT CONTINUING OVERLAP;Cf;0;BN;;;;;N;;;;; +1BCA2;SHORTHAND FORMAT DOWN STEP;Cf;0;BN;;;;;N;;;;; +1BCA3;SHORTHAND FORMAT UP STEP;Cf;0;BN;;;;;N;;;;; 1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;; 1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;; 1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;; @@ -22169,6 +24251,219 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; 1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; 1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; +1E800;MENDE KIKAKUI SYLLABLE M001 KI;Lo;0;R;;;;;N;;;;; +1E801;MENDE KIKAKUI SYLLABLE M002 KA;Lo;0;R;;;;;N;;;;; +1E802;MENDE KIKAKUI SYLLABLE M003 KU;Lo;0;R;;;;;N;;;;; +1E803;MENDE KIKAKUI SYLLABLE M065 KEE;Lo;0;R;;;;;N;;;;; +1E804;MENDE KIKAKUI SYLLABLE M095 KE;Lo;0;R;;;;;N;;;;; +1E805;MENDE KIKAKUI SYLLABLE M076 KOO;Lo;0;R;;;;;N;;;;; +1E806;MENDE KIKAKUI SYLLABLE M048 KO;Lo;0;R;;;;;N;;;;; +1E807;MENDE KIKAKUI SYLLABLE M179 KUA;Lo;0;R;;;;;N;;;;; +1E808;MENDE KIKAKUI SYLLABLE M004 WI;Lo;0;R;;;;;N;;;;; +1E809;MENDE KIKAKUI SYLLABLE M005 WA;Lo;0;R;;;;;N;;;;; +1E80A;MENDE KIKAKUI SYLLABLE M006 WU;Lo;0;R;;;;;N;;;;; +1E80B;MENDE KIKAKUI SYLLABLE M126 WEE;Lo;0;R;;;;;N;;;;; +1E80C;MENDE KIKAKUI SYLLABLE M118 WE;Lo;0;R;;;;;N;;;;; +1E80D;MENDE KIKAKUI SYLLABLE M114 WOO;Lo;0;R;;;;;N;;;;; +1E80E;MENDE KIKAKUI SYLLABLE M045 WO;Lo;0;R;;;;;N;;;;; +1E80F;MENDE KIKAKUI SYLLABLE M194 WUI;Lo;0;R;;;;;N;;;;; +1E810;MENDE KIKAKUI SYLLABLE M143 WEI;Lo;0;R;;;;;N;;;;; +1E811;MENDE KIKAKUI SYLLABLE M061 WVI;Lo;0;R;;;;;N;;;;; +1E812;MENDE KIKAKUI SYLLABLE M049 WVA;Lo;0;R;;;;;N;;;;; +1E813;MENDE KIKAKUI SYLLABLE M139 WVE;Lo;0;R;;;;;N;;;;; +1E814;MENDE KIKAKUI SYLLABLE M007 MIN;Lo;0;R;;;;;N;;;;; +1E815;MENDE KIKAKUI SYLLABLE M008 MAN;Lo;0;R;;;;;N;;;;; +1E816;MENDE KIKAKUI SYLLABLE M009 MUN;Lo;0;R;;;;;N;;;;; +1E817;MENDE KIKAKUI SYLLABLE M059 MEN;Lo;0;R;;;;;N;;;;; +1E818;MENDE KIKAKUI SYLLABLE M094 MON;Lo;0;R;;;;;N;;;;; +1E819;MENDE KIKAKUI SYLLABLE M154 MUAN;Lo;0;R;;;;;N;;;;; +1E81A;MENDE KIKAKUI SYLLABLE M189 MUEN;Lo;0;R;;;;;N;;;;; +1E81B;MENDE KIKAKUI SYLLABLE M010 BI;Lo;0;R;;;;;N;;;;; +1E81C;MENDE KIKAKUI SYLLABLE M011 BA;Lo;0;R;;;;;N;;;;; +1E81D;MENDE KIKAKUI SYLLABLE M012 BU;Lo;0;R;;;;;N;;;;; +1E81E;MENDE KIKAKUI SYLLABLE M150 BEE;Lo;0;R;;;;;N;;;;; +1E81F;MENDE KIKAKUI SYLLABLE M097 BE;Lo;0;R;;;;;N;;;;; +1E820;MENDE KIKAKUI SYLLABLE M103 BOO;Lo;0;R;;;;;N;;;;; +1E821;MENDE KIKAKUI SYLLABLE M138 BO;Lo;0;R;;;;;N;;;;; +1E822;MENDE KIKAKUI SYLLABLE M013 I;Lo;0;R;;;;;N;;;;; +1E823;MENDE KIKAKUI SYLLABLE M014 A;Lo;0;R;;;;;N;;;;; +1E824;MENDE KIKAKUI SYLLABLE M015 U;Lo;0;R;;;;;N;;;;; +1E825;MENDE KIKAKUI SYLLABLE M163 EE;Lo;0;R;;;;;N;;;;; +1E826;MENDE KIKAKUI SYLLABLE M100 E;Lo;0;R;;;;;N;;;;; +1E827;MENDE KIKAKUI SYLLABLE M165 OO;Lo;0;R;;;;;N;;;;; +1E828;MENDE KIKAKUI SYLLABLE M147 O;Lo;0;R;;;;;N;;;;; +1E829;MENDE KIKAKUI SYLLABLE M137 EI;Lo;0;R;;;;;N;;;;; +1E82A;MENDE KIKAKUI SYLLABLE M131 IN;Lo;0;R;;;;;N;;;;; +1E82B;MENDE KIKAKUI SYLLABLE M135 IN;Lo;0;R;;;;;N;;;;; +1E82C;MENDE KIKAKUI SYLLABLE M195 AN;Lo;0;R;;;;;N;;;;; +1E82D;MENDE KIKAKUI SYLLABLE M178 EN;Lo;0;R;;;;;N;;;;; +1E82E;MENDE KIKAKUI SYLLABLE M019 SI;Lo;0;R;;;;;N;;;;; +1E82F;MENDE KIKAKUI SYLLABLE M020 SA;Lo;0;R;;;;;N;;;;; +1E830;MENDE KIKAKUI SYLLABLE M021 SU;Lo;0;R;;;;;N;;;;; +1E831;MENDE KIKAKUI SYLLABLE M162 SEE;Lo;0;R;;;;;N;;;;; +1E832;MENDE KIKAKUI SYLLABLE M116 SE;Lo;0;R;;;;;N;;;;; +1E833;MENDE KIKAKUI SYLLABLE M136 SOO;Lo;0;R;;;;;N;;;;; +1E834;MENDE KIKAKUI SYLLABLE M079 SO;Lo;0;R;;;;;N;;;;; +1E835;MENDE KIKAKUI SYLLABLE M196 SIA;Lo;0;R;;;;;N;;;;; +1E836;MENDE KIKAKUI SYLLABLE M025 LI;Lo;0;R;;;;;N;;;;; +1E837;MENDE KIKAKUI SYLLABLE M026 LA;Lo;0;R;;;;;N;;;;; +1E838;MENDE KIKAKUI SYLLABLE M027 LU;Lo;0;R;;;;;N;;;;; +1E839;MENDE KIKAKUI SYLLABLE M084 LEE;Lo;0;R;;;;;N;;;;; +1E83A;MENDE KIKAKUI SYLLABLE M073 LE;Lo;0;R;;;;;N;;;;; +1E83B;MENDE KIKAKUI SYLLABLE M054 LOO;Lo;0;R;;;;;N;;;;; +1E83C;MENDE KIKAKUI SYLLABLE M153 LO;Lo;0;R;;;;;N;;;;; +1E83D;MENDE KIKAKUI SYLLABLE M110 LONG LE;Lo;0;R;;;;;N;;;;; +1E83E;MENDE KIKAKUI SYLLABLE M016 DI;Lo;0;R;;;;;N;;;;; +1E83F;MENDE KIKAKUI SYLLABLE M017 DA;Lo;0;R;;;;;N;;;;; +1E840;MENDE KIKAKUI SYLLABLE M018 DU;Lo;0;R;;;;;N;;;;; +1E841;MENDE KIKAKUI SYLLABLE M089 DEE;Lo;0;R;;;;;N;;;;; +1E842;MENDE KIKAKUI SYLLABLE M180 DOO;Lo;0;R;;;;;N;;;;; +1E843;MENDE KIKAKUI SYLLABLE M181 DO;Lo;0;R;;;;;N;;;;; +1E844;MENDE KIKAKUI SYLLABLE M022 TI;Lo;0;R;;;;;N;;;;; +1E845;MENDE KIKAKUI SYLLABLE M023 TA;Lo;0;R;;;;;N;;;;; +1E846;MENDE KIKAKUI SYLLABLE M024 TU;Lo;0;R;;;;;N;;;;; +1E847;MENDE KIKAKUI SYLLABLE M091 TEE;Lo;0;R;;;;;N;;;;; +1E848;MENDE KIKAKUI SYLLABLE M055 TE;Lo;0;R;;;;;N;;;;; +1E849;MENDE KIKAKUI SYLLABLE M104 TOO;Lo;0;R;;;;;N;;;;; +1E84A;MENDE KIKAKUI SYLLABLE M069 TO;Lo;0;R;;;;;N;;;;; +1E84B;MENDE KIKAKUI SYLLABLE M028 JI;Lo;0;R;;;;;N;;;;; +1E84C;MENDE KIKAKUI SYLLABLE M029 JA;Lo;0;R;;;;;N;;;;; +1E84D;MENDE KIKAKUI SYLLABLE M030 JU;Lo;0;R;;;;;N;;;;; +1E84E;MENDE KIKAKUI SYLLABLE M157 JEE;Lo;0;R;;;;;N;;;;; +1E84F;MENDE KIKAKUI SYLLABLE M113 JE;Lo;0;R;;;;;N;;;;; +1E850;MENDE KIKAKUI SYLLABLE M160 JOO;Lo;0;R;;;;;N;;;;; +1E851;MENDE KIKAKUI SYLLABLE M063 JO;Lo;0;R;;;;;N;;;;; +1E852;MENDE KIKAKUI SYLLABLE M175 LONG JO;Lo;0;R;;;;;N;;;;; +1E853;MENDE KIKAKUI SYLLABLE M031 YI;Lo;0;R;;;;;N;;;;; +1E854;MENDE KIKAKUI SYLLABLE M032 YA;Lo;0;R;;;;;N;;;;; +1E855;MENDE KIKAKUI SYLLABLE M033 YU;Lo;0;R;;;;;N;;;;; +1E856;MENDE KIKAKUI SYLLABLE M109 YEE;Lo;0;R;;;;;N;;;;; +1E857;MENDE KIKAKUI SYLLABLE M080 YE;Lo;0;R;;;;;N;;;;; +1E858;MENDE KIKAKUI SYLLABLE M141 YOO;Lo;0;R;;;;;N;;;;; +1E859;MENDE KIKAKUI SYLLABLE M121 YO;Lo;0;R;;;;;N;;;;; +1E85A;MENDE KIKAKUI SYLLABLE M034 FI;Lo;0;R;;;;;N;;;;; +1E85B;MENDE KIKAKUI SYLLABLE M035 FA;Lo;0;R;;;;;N;;;;; +1E85C;MENDE KIKAKUI SYLLABLE M036 FU;Lo;0;R;;;;;N;;;;; +1E85D;MENDE KIKAKUI SYLLABLE M078 FEE;Lo;0;R;;;;;N;;;;; +1E85E;MENDE KIKAKUI SYLLABLE M075 FE;Lo;0;R;;;;;N;;;;; +1E85F;MENDE KIKAKUI SYLLABLE M133 FOO;Lo;0;R;;;;;N;;;;; +1E860;MENDE KIKAKUI SYLLABLE M088 FO;Lo;0;R;;;;;N;;;;; +1E861;MENDE KIKAKUI SYLLABLE M197 FUA;Lo;0;R;;;;;N;;;;; +1E862;MENDE KIKAKUI SYLLABLE M101 FAN;Lo;0;R;;;;;N;;;;; +1E863;MENDE KIKAKUI SYLLABLE M037 NIN;Lo;0;R;;;;;N;;;;; +1E864;MENDE KIKAKUI SYLLABLE M038 NAN;Lo;0;R;;;;;N;;;;; +1E865;MENDE KIKAKUI SYLLABLE M039 NUN;Lo;0;R;;;;;N;;;;; +1E866;MENDE KIKAKUI SYLLABLE M117 NEN;Lo;0;R;;;;;N;;;;; +1E867;MENDE KIKAKUI SYLLABLE M169 NON;Lo;0;R;;;;;N;;;;; +1E868;MENDE KIKAKUI SYLLABLE M176 HI;Lo;0;R;;;;;N;;;;; +1E869;MENDE KIKAKUI SYLLABLE M041 HA;Lo;0;R;;;;;N;;;;; +1E86A;MENDE KIKAKUI SYLLABLE M186 HU;Lo;0;R;;;;;N;;;;; +1E86B;MENDE KIKAKUI SYLLABLE M040 HEE;Lo;0;R;;;;;N;;;;; +1E86C;MENDE KIKAKUI SYLLABLE M096 HE;Lo;0;R;;;;;N;;;;; +1E86D;MENDE KIKAKUI SYLLABLE M042 HOO;Lo;0;R;;;;;N;;;;; +1E86E;MENDE KIKAKUI SYLLABLE M140 HO;Lo;0;R;;;;;N;;;;; +1E86F;MENDE KIKAKUI SYLLABLE M083 HEEI;Lo;0;R;;;;;N;;;;; +1E870;MENDE KIKAKUI SYLLABLE M128 HOOU;Lo;0;R;;;;;N;;;;; +1E871;MENDE KIKAKUI SYLLABLE M053 HIN;Lo;0;R;;;;;N;;;;; +1E872;MENDE KIKAKUI SYLLABLE M130 HAN;Lo;0;R;;;;;N;;;;; +1E873;MENDE KIKAKUI SYLLABLE M087 HUN;Lo;0;R;;;;;N;;;;; +1E874;MENDE KIKAKUI SYLLABLE M052 HEN;Lo;0;R;;;;;N;;;;; +1E875;MENDE KIKAKUI SYLLABLE M193 HON;Lo;0;R;;;;;N;;;;; +1E876;MENDE KIKAKUI SYLLABLE M046 HUAN;Lo;0;R;;;;;N;;;;; +1E877;MENDE KIKAKUI SYLLABLE M090 NGGI;Lo;0;R;;;;;N;;;;; +1E878;MENDE KIKAKUI SYLLABLE M043 NGGA;Lo;0;R;;;;;N;;;;; +1E879;MENDE KIKAKUI SYLLABLE M082 NGGU;Lo;0;R;;;;;N;;;;; +1E87A;MENDE KIKAKUI SYLLABLE M115 NGGEE;Lo;0;R;;;;;N;;;;; +1E87B;MENDE KIKAKUI SYLLABLE M146 NGGE;Lo;0;R;;;;;N;;;;; +1E87C;MENDE KIKAKUI SYLLABLE M156 NGGOO;Lo;0;R;;;;;N;;;;; +1E87D;MENDE KIKAKUI SYLLABLE M120 NGGO;Lo;0;R;;;;;N;;;;; +1E87E;MENDE KIKAKUI SYLLABLE M159 NGGAA;Lo;0;R;;;;;N;;;;; +1E87F;MENDE KIKAKUI SYLLABLE M127 NGGUA;Lo;0;R;;;;;N;;;;; +1E880;MENDE KIKAKUI SYLLABLE M086 LONG NGGE;Lo;0;R;;;;;N;;;;; +1E881;MENDE KIKAKUI SYLLABLE M106 LONG NGGOO;Lo;0;R;;;;;N;;;;; +1E882;MENDE KIKAKUI SYLLABLE M183 LONG NGGO;Lo;0;R;;;;;N;;;;; +1E883;MENDE KIKAKUI SYLLABLE M155 GI;Lo;0;R;;;;;N;;;;; +1E884;MENDE KIKAKUI SYLLABLE M111 GA;Lo;0;R;;;;;N;;;;; +1E885;MENDE KIKAKUI SYLLABLE M168 GU;Lo;0;R;;;;;N;;;;; +1E886;MENDE KIKAKUI SYLLABLE M190 GEE;Lo;0;R;;;;;N;;;;; +1E887;MENDE KIKAKUI SYLLABLE M166 GUEI;Lo;0;R;;;;;N;;;;; +1E888;MENDE KIKAKUI SYLLABLE M167 GUAN;Lo;0;R;;;;;N;;;;; +1E889;MENDE KIKAKUI SYLLABLE M184 NGEN;Lo;0;R;;;;;N;;;;; +1E88A;MENDE KIKAKUI SYLLABLE M057 NGON;Lo;0;R;;;;;N;;;;; +1E88B;MENDE KIKAKUI SYLLABLE M177 NGUAN;Lo;0;R;;;;;N;;;;; +1E88C;MENDE KIKAKUI SYLLABLE M068 PI;Lo;0;R;;;;;N;;;;; +1E88D;MENDE KIKAKUI SYLLABLE M099 PA;Lo;0;R;;;;;N;;;;; +1E88E;MENDE KIKAKUI SYLLABLE M050 PU;Lo;0;R;;;;;N;;;;; +1E88F;MENDE KIKAKUI SYLLABLE M081 PEE;Lo;0;R;;;;;N;;;;; +1E890;MENDE KIKAKUI SYLLABLE M051 PE;Lo;0;R;;;;;N;;;;; +1E891;MENDE KIKAKUI SYLLABLE M102 POO;Lo;0;R;;;;;N;;;;; +1E892;MENDE KIKAKUI SYLLABLE M066 PO;Lo;0;R;;;;;N;;;;; +1E893;MENDE KIKAKUI SYLLABLE M145 MBI;Lo;0;R;;;;;N;;;;; +1E894;MENDE KIKAKUI SYLLABLE M062 MBA;Lo;0;R;;;;;N;;;;; +1E895;MENDE KIKAKUI SYLLABLE M122 MBU;Lo;0;R;;;;;N;;;;; +1E896;MENDE KIKAKUI SYLLABLE M047 MBEE;Lo;0;R;;;;;N;;;;; +1E897;MENDE KIKAKUI SYLLABLE M188 MBEE;Lo;0;R;;;;;N;;;;; +1E898;MENDE KIKAKUI SYLLABLE M072 MBE;Lo;0;R;;;;;N;;;;; +1E899;MENDE KIKAKUI SYLLABLE M172 MBOO;Lo;0;R;;;;;N;;;;; +1E89A;MENDE KIKAKUI SYLLABLE M174 MBO;Lo;0;R;;;;;N;;;;; +1E89B;MENDE KIKAKUI SYLLABLE M187 MBUU;Lo;0;R;;;;;N;;;;; +1E89C;MENDE KIKAKUI SYLLABLE M161 LONG MBE;Lo;0;R;;;;;N;;;;; +1E89D;MENDE KIKAKUI SYLLABLE M105 LONG MBOO;Lo;0;R;;;;;N;;;;; +1E89E;MENDE KIKAKUI SYLLABLE M142 LONG MBO;Lo;0;R;;;;;N;;;;; +1E89F;MENDE KIKAKUI SYLLABLE M132 KPI;Lo;0;R;;;;;N;;;;; +1E8A0;MENDE KIKAKUI SYLLABLE M092 KPA;Lo;0;R;;;;;N;;;;; +1E8A1;MENDE KIKAKUI SYLLABLE M074 KPU;Lo;0;R;;;;;N;;;;; +1E8A2;MENDE KIKAKUI SYLLABLE M044 KPEE;Lo;0;R;;;;;N;;;;; +1E8A3;MENDE KIKAKUI SYLLABLE M108 KPE;Lo;0;R;;;;;N;;;;; +1E8A4;MENDE KIKAKUI SYLLABLE M112 KPOO;Lo;0;R;;;;;N;;;;; +1E8A5;MENDE KIKAKUI SYLLABLE M158 KPO;Lo;0;R;;;;;N;;;;; +1E8A6;MENDE KIKAKUI SYLLABLE M124 GBI;Lo;0;R;;;;;N;;;;; +1E8A7;MENDE KIKAKUI SYLLABLE M056 GBA;Lo;0;R;;;;;N;;;;; +1E8A8;MENDE KIKAKUI SYLLABLE M148 GBU;Lo;0;R;;;;;N;;;;; +1E8A9;MENDE KIKAKUI SYLLABLE M093 GBEE;Lo;0;R;;;;;N;;;;; +1E8AA;MENDE KIKAKUI SYLLABLE M107 GBE;Lo;0;R;;;;;N;;;;; +1E8AB;MENDE KIKAKUI SYLLABLE M071 GBOO;Lo;0;R;;;;;N;;;;; +1E8AC;MENDE KIKAKUI SYLLABLE M070 GBO;Lo;0;R;;;;;N;;;;; +1E8AD;MENDE KIKAKUI SYLLABLE M171 RA;Lo;0;R;;;;;N;;;;; +1E8AE;MENDE KIKAKUI SYLLABLE M123 NDI;Lo;0;R;;;;;N;;;;; +1E8AF;MENDE KIKAKUI SYLLABLE M129 NDA;Lo;0;R;;;;;N;;;;; +1E8B0;MENDE KIKAKUI SYLLABLE M125 NDU;Lo;0;R;;;;;N;;;;; +1E8B1;MENDE KIKAKUI SYLLABLE M191 NDEE;Lo;0;R;;;;;N;;;;; +1E8B2;MENDE KIKAKUI SYLLABLE M119 NDE;Lo;0;R;;;;;N;;;;; +1E8B3;MENDE KIKAKUI SYLLABLE M067 NDOO;Lo;0;R;;;;;N;;;;; +1E8B4;MENDE KIKAKUI SYLLABLE M064 NDO;Lo;0;R;;;;;N;;;;; +1E8B5;MENDE KIKAKUI SYLLABLE M152 NJA;Lo;0;R;;;;;N;;;;; +1E8B6;MENDE KIKAKUI SYLLABLE M192 NJU;Lo;0;R;;;;;N;;;;; +1E8B7;MENDE KIKAKUI SYLLABLE M149 NJEE;Lo;0;R;;;;;N;;;;; +1E8B8;MENDE KIKAKUI SYLLABLE M134 NJOO;Lo;0;R;;;;;N;;;;; +1E8B9;MENDE KIKAKUI SYLLABLE M182 VI;Lo;0;R;;;;;N;;;;; +1E8BA;MENDE KIKAKUI SYLLABLE M185 VA;Lo;0;R;;;;;N;;;;; +1E8BB;MENDE KIKAKUI SYLLABLE M151 VU;Lo;0;R;;;;;N;;;;; +1E8BC;MENDE KIKAKUI SYLLABLE M173 VEE;Lo;0;R;;;;;N;;;;; +1E8BD;MENDE KIKAKUI SYLLABLE M085 VE;Lo;0;R;;;;;N;;;;; +1E8BE;MENDE KIKAKUI SYLLABLE M144 VOO;Lo;0;R;;;;;N;;;;; +1E8BF;MENDE KIKAKUI SYLLABLE M077 VO;Lo;0;R;;;;;N;;;;; +1E8C0;MENDE KIKAKUI SYLLABLE M164 NYIN;Lo;0;R;;;;;N;;;;; +1E8C1;MENDE KIKAKUI SYLLABLE M058 NYAN;Lo;0;R;;;;;N;;;;; +1E8C2;MENDE KIKAKUI SYLLABLE M170 NYUN;Lo;0;R;;;;;N;;;;; +1E8C3;MENDE KIKAKUI SYLLABLE M098 NYEN;Lo;0;R;;;;;N;;;;; +1E8C4;MENDE KIKAKUI SYLLABLE M060 NYON;Lo;0;R;;;;;N;;;;; +1E8C7;MENDE KIKAKUI DIGIT ONE;No;0;R;;;;1;N;;;;; +1E8C8;MENDE KIKAKUI DIGIT TWO;No;0;R;;;;2;N;;;;; +1E8C9;MENDE KIKAKUI DIGIT THREE;No;0;R;;;;3;N;;;;; +1E8CA;MENDE KIKAKUI DIGIT FOUR;No;0;R;;;;4;N;;;;; +1E8CB;MENDE KIKAKUI DIGIT FIVE;No;0;R;;;;5;N;;;;; +1E8CC;MENDE KIKAKUI DIGIT SIX;No;0;R;;;;6;N;;;;; +1E8CD;MENDE KIKAKUI DIGIT SEVEN;No;0;R;;;;7;N;;;;; +1E8CE;MENDE KIKAKUI DIGIT EIGHT;No;0;R;;;;8;N;;;;; +1E8CF;MENDE KIKAKUI DIGIT NINE;No;0;R;;;;9;N;;;;; +1E8D0;MENDE KIKAKUI COMBINING NUMBER TEENS;Mn;220;NSM;;;;;N;;;;; +1E8D1;MENDE KIKAKUI COMBINING NUMBER TENS;Mn;220;NSM;;;;;N;;;;; +1E8D2;MENDE KIKAKUI COMBINING NUMBER HUNDREDS;Mn;220;NSM;;;;;N;;;;; +1E8D3;MENDE KIKAKUI COMBINING NUMBER THOUSANDS;Mn;220;NSM;;;;;N;;;;; +1E8D4;MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS;Mn;220;NSM;;;;;N;;;;; +1E8D5;MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS;Mn;220;NSM;;;;;N;;;;; +1E8D6;MENDE KIKAKUI COMBINING NUMBER MILLIONS;Mn;220;NSM;;;;;N;;;;; 1EE00;ARABIC MATHEMATICAL ALEF;Lo;0;AL;<font> 0627;;;;N;;;;; 1EE01;ARABIC MATHEMATICAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;; 1EE02;ARABIC MATHEMATICAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; @@ -22485,6 +24780,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F0BC;PLAYING CARD KNIGHT OF HEARTS;So;0;ON;;;;;N;;;;; 1F0BD;PLAYING CARD QUEEN OF HEARTS;So;0;ON;;;;;N;;;;; 1F0BE;PLAYING CARD KING OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BF;PLAYING CARD RED JOKER;So;0;ON;;;;;N;;;;; 1F0C1;PLAYING CARD ACE OF DIAMONDS;So;0;ON;;;;;N;;;;; 1F0C2;PLAYING CARD TWO OF DIAMONDS;So;0;ON;;;;;N;;;;; 1F0C3;PLAYING CARD THREE OF DIAMONDS;So;0;ON;;;;;N;;;;; @@ -22515,6 +24811,28 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F0DD;PLAYING CARD QUEEN OF CLUBS;So;0;ON;;;;;N;;;;; 1F0DE;PLAYING CARD KING OF CLUBS;So;0;ON;;;;;N;;;;; 1F0DF;PLAYING CARD WHITE JOKER;So;0;ON;;;;;N;;;;; +1F0E0;PLAYING CARD FOOL;So;0;ON;;;;;N;;;;; +1F0E1;PLAYING CARD TRUMP-1;So;0;ON;;;;;N;;;;; +1F0E2;PLAYING CARD TRUMP-2;So;0;ON;;;;;N;;;;; +1F0E3;PLAYING CARD TRUMP-3;So;0;ON;;;;;N;;;;; +1F0E4;PLAYING CARD TRUMP-4;So;0;ON;;;;;N;;;;; +1F0E5;PLAYING CARD TRUMP-5;So;0;ON;;;;;N;;;;; +1F0E6;PLAYING CARD TRUMP-6;So;0;ON;;;;;N;;;;; +1F0E7;PLAYING CARD TRUMP-7;So;0;ON;;;;;N;;;;; +1F0E8;PLAYING CARD TRUMP-8;So;0;ON;;;;;N;;;;; +1F0E9;PLAYING CARD TRUMP-9;So;0;ON;;;;;N;;;;; +1F0EA;PLAYING CARD TRUMP-10;So;0;ON;;;;;N;;;;; +1F0EB;PLAYING CARD TRUMP-11;So;0;ON;;;;;N;;;;; +1F0EC;PLAYING CARD TRUMP-12;So;0;ON;;;;;N;;;;; +1F0ED;PLAYING CARD TRUMP-13;So;0;ON;;;;;N;;;;; +1F0EE;PLAYING CARD TRUMP-14;So;0;ON;;;;;N;;;;; +1F0EF;PLAYING CARD TRUMP-15;So;0;ON;;;;;N;;;;; +1F0F0;PLAYING CARD TRUMP-16;So;0;ON;;;;;N;;;;; +1F0F1;PLAYING CARD TRUMP-17;So;0;ON;;;;;N;;;;; +1F0F2;PLAYING CARD TRUMP-18;So;0;ON;;;;;N;;;;; +1F0F3;PLAYING CARD TRUMP-19;So;0;ON;;;;;N;;;;; +1F0F4;PLAYING CARD TRUMP-20;So;0;ON;;;;;N;;;;; +1F0F5;PLAYING CARD TRUMP-21;So;0;ON;;;;;N;;;;; 1F100;DIGIT ZERO FULL STOP;No;0;EN;<compat> 0030 002E;;0;0;N;;;;; 1F101;DIGIT ZERO COMMA;No;0;EN;<compat> 0030 002C;;0;0;N;;;;; 1F102;DIGIT ONE COMMA;No;0;EN;<compat> 0031 002C;;1;1;N;;;;; @@ -22526,6 +24844,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F108;DIGIT SEVEN COMMA;No;0;EN;<compat> 0037 002C;;7;7;N;;;;; 1F109;DIGIT EIGHT COMMA;No;0;EN;<compat> 0038 002C;;8;8;N;;;;; 1F10A;DIGIT NINE COMMA;No;0;EN;<compat> 0039 002C;;9;9;N;;;;; +1F10B;DINGBAT CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;; +1F10C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;; 1F110;PARENTHESIZED LATIN CAPITAL LETTER A;So;0;L;<compat> 0028 0041 0029;;;;N;;;;; 1F111;PARENTHESIZED LATIN CAPITAL LETTER B;So;0;L;<compat> 0028 0042 0029;;;;N;;;;; 1F112;PARENTHESIZED LATIN CAPITAL LETTER C;So;0;L;<compat> 0028 0043 0029;;;;N;;;;; @@ -22776,12 +25096,25 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F31E;SUN WITH FACE;So;0;ON;;;;;N;;;;; 1F31F;GLOWING STAR;So;0;ON;;;;;N;;;;; 1F320;SHOOTING STAR;So;0;ON;;;;;N;;;;; +1F321;THERMOMETER;So;0;ON;;;;;N;;;;; +1F322;BLACK DROPLET;So;0;ON;;;;;N;;;;; +1F323;WHITE SUN;So;0;ON;;;;;N;;;;; +1F324;WHITE SUN WITH SMALL CLOUD;So;0;ON;;;;;N;;;;; +1F325;WHITE SUN BEHIND CLOUD;So;0;ON;;;;;N;;;;; +1F326;WHITE SUN BEHIND CLOUD WITH RAIN;So;0;ON;;;;;N;;;;; +1F327;CLOUD WITH RAIN;So;0;ON;;;;;N;;;;; +1F328;CLOUD WITH SNOW;So;0;ON;;;;;N;;;;; +1F329;CLOUD WITH LIGHTNING;So;0;ON;;;;;N;;;;; +1F32A;CLOUD WITH TORNADO;So;0;ON;;;;;N;;;;; +1F32B;FOG;So;0;ON;;;;;N;;;;; +1F32C;WIND BLOWING FACE;So;0;ON;;;;;N;;;;; 1F330;CHESTNUT;So;0;ON;;;;;N;;;;; 1F331;SEEDLING;So;0;ON;;;;;N;;;;; 1F332;EVERGREEN TREE;So;0;ON;;;;;N;;;;; 1F333;DECIDUOUS TREE;So;0;ON;;;;;N;;;;; 1F334;PALM TREE;So;0;ON;;;;;N;;;;; 1F335;CACTUS;So;0;ON;;;;;N;;;;; +1F336;HOT PEPPER;So;0;ON;;;;;N;;;;; 1F337;TULIP;So;0;ON;;;;;N;;;;; 1F338;CHERRY BLOSSOM;So;0;ON;;;;;N;;;;; 1F339;ROSE;So;0;ON;;;;;N;;;;; @@ -22852,6 +25185,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F37A;BEER MUG;So;0;ON;;;;;N;;;;; 1F37B;CLINKING BEER MUGS;So;0;ON;;;;;N;;;;; 1F37C;BABY BOTTLE;So;0;ON;;;;;N;;;;; +1F37D;FORK AND KNIFE WITH PLATE;So;0;ON;;;;;N;;;;; 1F380;RIBBON;So;0;ON;;;;;N;;;;; 1F381;WRAPPED PRESENT;So;0;ON;;;;;N;;;;; 1F382;BIRTHDAY CAKE;So;0;ON;;;;;N;;;;; @@ -22872,6 +25206,18 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F391;MOON VIEWING CEREMONY;So;0;ON;;;;;N;;;;; 1F392;SCHOOL SATCHEL;So;0;ON;;;;;N;;;;; 1F393;GRADUATION CAP;So;0;ON;;;;;N;;;;; +1F394;HEART WITH TIP ON THE LEFT;So;0;ON;;;;;N;;;;; +1F395;BOUQUET OF FLOWERS;So;0;ON;;;;;N;;;;; +1F396;MILITARY MEDAL;So;0;ON;;;;;N;;;;; +1F397;REMINDER RIBBON;So;0;ON;;;;;N;;;;; +1F398;MUSICAL KEYBOARD WITH JACKS;So;0;ON;;;;;N;;;;; +1F399;STUDIO MICROPHONE;So;0;ON;;;;;N;;;;; +1F39A;LEVEL SLIDER;So;0;ON;;;;;N;;;;; +1F39B;CONTROL KNOBS;So;0;ON;;;;;N;;;;; +1F39C;BEAMED ASCENDING MUSICAL NOTES;So;0;ON;;;;;N;;;;; +1F39D;BEAMED DESCENDING MUSICAL NOTES;So;0;ON;;;;;N;;;;; +1F39E;FILM FRAMES;So;0;ON;;;;;N;;;;; +1F39F;ADMISSION TICKETS;So;0;ON;;;;;N;;;;; 1F3A0;CAROUSEL HORSE;So;0;ON;;;;;N;;;;; 1F3A1;FERRIS WHEEL;So;0;ON;;;;;N;;;;; 1F3A2;ROLLER COASTER;So;0;ON;;;;;N;;;;; @@ -22909,11 +25255,28 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F3C2;SNOWBOARDER;So;0;ON;;;;;N;;;;; 1F3C3;RUNNER;So;0;ON;;;;;N;;;;; 1F3C4;SURFER;So;0;ON;;;;;N;;;;; +1F3C5;SPORTS MEDAL;So;0;ON;;;;;N;;;;; 1F3C6;TROPHY;So;0;ON;;;;;N;;;;; 1F3C7;HORSE RACING;So;0;ON;;;;;N;;;;; 1F3C8;AMERICAN FOOTBALL;So;0;ON;;;;;N;;;;; 1F3C9;RUGBY FOOTBALL;So;0;ON;;;;;N;;;;; 1F3CA;SWIMMER;So;0;ON;;;;;N;;;;; +1F3CB;WEIGHT LIFTER;So;0;ON;;;;;N;;;;; +1F3CC;GOLFER;So;0;ON;;;;;N;;;;; +1F3CD;RACING MOTORCYCLE;So;0;ON;;;;;N;;;;; +1F3CE;RACING CAR;So;0;ON;;;;;N;;;;; +1F3D4;SNOW CAPPED MOUNTAIN;So;0;ON;;;;;N;;;;; +1F3D5;CAMPING;So;0;ON;;;;;N;;;;; +1F3D6;BEACH WITH UMBRELLA;So;0;ON;;;;;N;;;;; +1F3D7;BUILDING CONSTRUCTION;So;0;ON;;;;;N;;;;; +1F3D8;HOUSE BUILDINGS;So;0;ON;;;;;N;;;;; +1F3D9;CITYSCAPE;So;0;ON;;;;;N;;;;; +1F3DA;DERELICT HOUSE BUILDING;So;0;ON;;;;;N;;;;; +1F3DB;CLASSICAL BUILDING;So;0;ON;;;;;N;;;;; +1F3DC;DESERT;So;0;ON;;;;;N;;;;; +1F3DD;DESERT ISLAND;So;0;ON;;;;;N;;;;; +1F3DE;NATIONAL PARK;So;0;ON;;;;;N;;;;; +1F3DF;STADIUM;So;0;ON;;;;;N;;;;; 1F3E0;HOUSE BUILDING;So;0;ON;;;;;N;;;;; 1F3E1;HOUSE WITH GARDEN;So;0;ON;;;;;N;;;;; 1F3E2;OFFICE BUILDING;So;0;ON;;;;;N;;;;; @@ -22931,6 +25294,13 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F3EE;IZAKAYA LANTERN;So;0;ON;;;;;N;;;;; 1F3EF;JAPANESE CASTLE;So;0;ON;;;;;N;;;;; 1F3F0;EUROPEAN CASTLE;So;0;ON;;;;;N;;;;; +1F3F1;WHITE PENNANT;So;0;ON;;;;;N;;;;; +1F3F2;BLACK PENNANT;So;0;ON;;;;;N;;;;; +1F3F3;WAVING WHITE FLAG;So;0;ON;;;;;N;;;;; +1F3F4;WAVING BLACK FLAG;So;0;ON;;;;;N;;;;; +1F3F5;ROSETTE;So;0;ON;;;;;N;;;;; +1F3F6;BLACK ROSETTE;So;0;ON;;;;;N;;;;; +1F3F7;LABEL;So;0;ON;;;;;N;;;;; 1F400;RAT;So;0;ON;;;;;N;;;;; 1F401;MOUSE;So;0;ON;;;;;N;;;;; 1F402;OX;So;0;ON;;;;;N;;;;; @@ -22994,7 +25364,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F43C;PANDA FACE;So;0;ON;;;;;N;;;;; 1F43D;PIG NOSE;So;0;ON;;;;;N;;;;; 1F43E;PAW PRINTS;So;0;ON;;;;;N;;;;; +1F43F;CHIPMUNK;So;0;ON;;;;;N;;;;; 1F440;EYES;So;0;ON;;;;;N;;;;; +1F441;EYE;So;0;ON;;;;;N;;;;; 1F442;EAR;So;0;ON;;;;;N;;;;; 1F443;NOSE;So;0;ON;;;;;N;;;;; 1F444;MOUTH;So;0;ON;;;;;N;;;;; @@ -23177,10 +25549,13 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F4F5;NO MOBILE PHONES;So;0;ON;;;;;N;;;;; 1F4F6;ANTENNA WITH BARS;So;0;ON;;;;;N;;;;; 1F4F7;CAMERA;So;0;ON;;;;;N;;;;; +1F4F8;CAMERA WITH FLASH;So;0;ON;;;;;N;;;;; 1F4F9;VIDEO CAMERA;So;0;ON;;;;;N;;;;; 1F4FA;TELEVISION;So;0;ON;;;;;N;;;;; 1F4FB;RADIO;So;0;ON;;;;;N;;;;; 1F4FC;VIDEOCASSETTE;So;0;ON;;;;;N;;;;; +1F4FD;FILM PROJECTOR;So;0;ON;;;;;N;;;;; +1F4FE;PORTABLE STEREO;So;0;ON;;;;;N;;;;; 1F500;TWISTED RIGHTWARDS ARROWS;So;0;ON;;;;;N;;;;; 1F501;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;; 1F502;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS WITH CIRCLED ONE OVERLAY;So;0;ON;;;;;N;;;;; @@ -23243,10 +25618,19 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F53B;DOWN-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;; 1F53C;UP-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;; 1F53D;DOWN-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;; +1F53E;LOWER RIGHT SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F53F;UPPER RIGHT SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; 1F540;CIRCLED CROSS POMMEE;So;0;ON;;;;;N;;;;; 1F541;CROSS POMMEE WITH HALF-CIRCLE BELOW;So;0;ON;;;;;N;;;;; 1F542;CROSS POMMEE;So;0;ON;;;;;N;;;;; 1F543;NOTCHED LEFT SEMICIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;; +1F544;NOTCHED RIGHT SEMICIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;; +1F545;SYMBOL FOR MARKS CHAPTER;So;0;ON;;;;;N;;;;; +1F546;WHITE LATIN CROSS;So;0;ON;;;;;N;;;;; +1F547;HEAVY LATIN CROSS;So;0;ON;;;;;N;;;;; +1F548;CELTIC CROSS;So;0;ON;;;;;N;;;;; +1F549;OM SYMBOL;So;0;ON;;;;;N;;;;; +1F54A;DOVE OF PEACE;So;0;ON;;;;;N;;;;; 1F550;CLOCK FACE ONE OCLOCK;So;0;ON;;;;;N;;;;; 1F551;CLOCK FACE TWO OCLOCK;So;0;ON;;;;;N;;;;; 1F552;CLOCK FACE THREE OCLOCK;So;0;ON;;;;;N;;;;; @@ -23271,6 +25655,151 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F565;CLOCK FACE TEN-THIRTY;So;0;ON;;;;;N;;;;; 1F566;CLOCK FACE ELEVEN-THIRTY;So;0;ON;;;;;N;;;;; 1F567;CLOCK FACE TWELVE-THIRTY;So;0;ON;;;;;N;;;;; +1F568;RIGHT SPEAKER;So;0;ON;;;;;N;;;;; +1F569;RIGHT SPEAKER WITH ONE SOUND WAVE;So;0;ON;;;;;N;;;;; +1F56A;RIGHT SPEAKER WITH THREE SOUND WAVES;So;0;ON;;;;;N;;;;; +1F56B;BULLHORN;So;0;ON;;;;;N;;;;; +1F56C;BULLHORN WITH SOUND WAVES;So;0;ON;;;;;N;;;;; +1F56D;RINGING BELL;So;0;ON;;;;;N;;;;; +1F56E;BOOK;So;0;ON;;;;;N;;;;; +1F56F;CANDLE;So;0;ON;;;;;N;;;;; +1F570;MANTELPIECE CLOCK;So;0;ON;;;;;N;;;;; +1F571;BLACK SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;; +1F572;NO PIRACY;So;0;ON;;;;;N;;;;; +1F573;HOLE;So;0;ON;;;;;N;;;;; +1F574;MAN IN BUSINESS SUIT LEVITATING;So;0;ON;;;;;N;;;;; +1F575;SLEUTH OR SPY;So;0;ON;;;;;N;;;;; +1F576;DARK SUNGLASSES;So;0;ON;;;;;N;;;;; +1F577;SPIDER;So;0;ON;;;;;N;;;;; +1F578;SPIDER WEB;So;0;ON;;;;;N;;;;; +1F579;JOYSTICK;So;0;ON;;;;;N;;;;; +1F57B;LEFT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; +1F57C;TELEPHONE RECEIVER WITH PAGE;So;0;ON;;;;;N;;;;; +1F57D;RIGHT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; +1F57E;WHITE TOUCHTONE TELEPHONE;So;0;ON;;;;;N;;;;; +1F57F;BLACK TOUCHTONE TELEPHONE;So;0;ON;;;;;N;;;;; +1F580;TELEPHONE ON TOP OF MODEM;So;0;ON;;;;;N;;;;; +1F581;CLAMSHELL MOBILE PHONE;So;0;ON;;;;;N;;;;; +1F582;BACK OF ENVELOPE;So;0;ON;;;;;N;;;;; +1F583;STAMPED ENVELOPE;So;0;ON;;;;;N;;;;; +1F584;ENVELOPE WITH LIGHTNING;So;0;ON;;;;;N;;;;; +1F585;FLYING ENVELOPE;So;0;ON;;;;;N;;;;; +1F586;PEN OVER STAMPED ENVELOPE;So;0;ON;;;;;N;;;;; +1F587;LINKED PAPERCLIPS;So;0;ON;;;;;N;;;;; +1F588;BLACK PUSHPIN;So;0;ON;;;;;N;;;;; +1F589;LOWER LEFT PENCIL;So;0;ON;;;;;N;;;;; +1F58A;LOWER LEFT BALLPOINT PEN;So;0;ON;;;;;N;;;;; +1F58B;LOWER LEFT FOUNTAIN PEN;So;0;ON;;;;;N;;;;; +1F58C;LOWER LEFT PAINTBRUSH;So;0;ON;;;;;N;;;;; +1F58D;LOWER LEFT CRAYON;So;0;ON;;;;;N;;;;; +1F58E;LEFT WRITING HAND;So;0;ON;;;;;N;;;;; +1F58F;TURNED OK HAND SIGN;So;0;ON;;;;;N;;;;; +1F590;RAISED HAND WITH FINGERS SPLAYED;So;0;ON;;;;;N;;;;; +1F591;REVERSED RAISED HAND WITH FINGERS SPLAYED;So;0;ON;;;;;N;;;;; +1F592;REVERSED THUMBS UP SIGN;So;0;ON;;;;;N;;;;; +1F593;REVERSED THUMBS DOWN SIGN;So;0;ON;;;;;N;;;;; +1F594;REVERSED VICTORY HAND;So;0;ON;;;;;N;;;;; +1F595;REVERSED HAND WITH MIDDLE FINGER EXTENDED;So;0;ON;;;;;N;;;;; +1F596;RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS;So;0;ON;;;;;N;;;;; +1F597;WHITE DOWN POINTING LEFT HAND INDEX;So;0;ON;;;;;N;;;;; +1F598;SIDEWAYS WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; +1F599;SIDEWAYS WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +1F59A;SIDEWAYS BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; +1F59B;SIDEWAYS BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +1F59C;BLACK LEFT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F59D;BLACK RIGHT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F59E;SIDEWAYS WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;; +1F59F;SIDEWAYS WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; +1F5A0;SIDEWAYS BLACK UP POINTING INDEX;So;0;ON;;;;;N;;;;; +1F5A1;SIDEWAYS BLACK DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; +1F5A2;BLACK UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F5A3;BLACK DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F5A5;DESKTOP COMPUTER;So;0;ON;;;;;N;;;;; +1F5A6;KEYBOARD AND MOUSE;So;0;ON;;;;;N;;;;; +1F5A7;THREE NETWORKED COMPUTERS;So;0;ON;;;;;N;;;;; +1F5A8;PRINTER;So;0;ON;;;;;N;;;;; +1F5A9;POCKET CALCULATOR;So;0;ON;;;;;N;;;;; +1F5AA;BLACK HARD SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;; +1F5AB;WHITE HARD SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;; +1F5AC;SOFT SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;; +1F5AD;TAPE CARTRIDGE;So;0;ON;;;;;N;;;;; +1F5AE;WIRED KEYBOARD;So;0;ON;;;;;N;;;;; +1F5AF;ONE BUTTON MOUSE;So;0;ON;;;;;N;;;;; +1F5B0;TWO BUTTON MOUSE;So;0;ON;;;;;N;;;;; +1F5B1;THREE BUTTON MOUSE;So;0;ON;;;;;N;;;;; +1F5B2;TRACKBALL;So;0;ON;;;;;N;;;;; +1F5B3;OLD PERSONAL COMPUTER;So;0;ON;;;;;N;;;;; +1F5B4;HARD DISK;So;0;ON;;;;;N;;;;; +1F5B5;SCREEN;So;0;ON;;;;;N;;;;; +1F5B6;PRINTER ICON;So;0;ON;;;;;N;;;;; +1F5B7;FAX ICON;So;0;ON;;;;;N;;;;; +1F5B8;OPTICAL DISC ICON;So;0;ON;;;;;N;;;;; +1F5B9;DOCUMENT WITH TEXT;So;0;ON;;;;;N;;;;; +1F5BA;DOCUMENT WITH TEXT AND PICTURE;So;0;ON;;;;;N;;;;; +1F5BB;DOCUMENT WITH PICTURE;So;0;ON;;;;;N;;;;; +1F5BC;FRAME WITH PICTURE;So;0;ON;;;;;N;;;;; +1F5BD;FRAME WITH TILES;So;0;ON;;;;;N;;;;; +1F5BE;FRAME WITH AN X;So;0;ON;;;;;N;;;;; +1F5BF;BLACK FOLDER;So;0;ON;;;;;N;;;;; +1F5C0;FOLDER;So;0;ON;;;;;N;;;;; +1F5C1;OPEN FOLDER;So;0;ON;;;;;N;;;;; +1F5C2;CARD INDEX DIVIDERS;So;0;ON;;;;;N;;;;; +1F5C3;CARD FILE BOX;So;0;ON;;;;;N;;;;; +1F5C4;FILE CABINET;So;0;ON;;;;;N;;;;; +1F5C5;EMPTY NOTE;So;0;ON;;;;;N;;;;; +1F5C6;EMPTY NOTE PAGE;So;0;ON;;;;;N;;;;; +1F5C7;EMPTY NOTE PAD;So;0;ON;;;;;N;;;;; +1F5C8;NOTE;So;0;ON;;;;;N;;;;; +1F5C9;NOTE PAGE;So;0;ON;;;;;N;;;;; +1F5CA;NOTE PAD;So;0;ON;;;;;N;;;;; +1F5CB;EMPTY DOCUMENT;So;0;ON;;;;;N;;;;; +1F5CC;EMPTY PAGE;So;0;ON;;;;;N;;;;; +1F5CD;EMPTY PAGES;So;0;ON;;;;;N;;;;; +1F5CE;DOCUMENT;So;0;ON;;;;;N;;;;; +1F5CF;PAGE;So;0;ON;;;;;N;;;;; +1F5D0;PAGES;So;0;ON;;;;;N;;;;; +1F5D1;WASTEBASKET;So;0;ON;;;;;N;;;;; +1F5D2;SPIRAL NOTE PAD;So;0;ON;;;;;N;;;;; +1F5D3;SPIRAL CALENDAR PAD;So;0;ON;;;;;N;;;;; +1F5D4;DESKTOP WINDOW;So;0;ON;;;;;N;;;;; +1F5D5;MINIMIZE;So;0;ON;;;;;N;;;;; +1F5D6;MAXIMIZE;So;0;ON;;;;;N;;;;; +1F5D7;OVERLAP;So;0;ON;;;;;N;;;;; +1F5D8;CLOCKWISE RIGHT AND LEFT SEMICIRCLE ARROWS;So;0;ON;;;;;N;;;;; +1F5D9;CANCELLATION X;So;0;ON;;;;;N;;;;; +1F5DA;INCREASE FONT SIZE SYMBOL;So;0;ON;;;;;N;;;;; +1F5DB;DECREASE FONT SIZE SYMBOL;So;0;ON;;;;;N;;;;; +1F5DC;COMPRESSION;So;0;ON;;;;;N;;;;; +1F5DD;OLD KEY;So;0;ON;;;;;N;;;;; +1F5DE;ROLLED-UP NEWSPAPER;So;0;ON;;;;;N;;;;; +1F5DF;PAGE WITH CIRCLED TEXT;So;0;ON;;;;;N;;;;; +1F5E0;STOCK CHART;So;0;ON;;;;;N;;;;; +1F5E1;DAGGER KNIFE;So;0;ON;;;;;N;;;;; +1F5E2;LIPS;So;0;ON;;;;;N;;;;; +1F5E3;SPEAKING HEAD IN SILHOUETTE;So;0;ON;;;;;N;;;;; +1F5E4;THREE RAYS ABOVE;So;0;ON;;;;;N;;;;; +1F5E5;THREE RAYS BELOW;So;0;ON;;;;;N;;;;; +1F5E6;THREE RAYS LEFT;So;0;ON;;;;;N;;;;; +1F5E7;THREE RAYS RIGHT;So;0;ON;;;;;N;;;;; +1F5E8;LEFT SPEECH BUBBLE;So;0;ON;;;;;N;;;;; +1F5E9;RIGHT SPEECH BUBBLE;So;0;ON;;;;;N;;;;; +1F5EA;TWO SPEECH BUBBLES;So;0;ON;;;;;N;;;;; +1F5EB;THREE SPEECH BUBBLES;So;0;ON;;;;;N;;;;; +1F5EC;LEFT THOUGHT BUBBLE;So;0;ON;;;;;N;;;;; +1F5ED;RIGHT THOUGHT BUBBLE;So;0;ON;;;;;N;;;;; +1F5EE;LEFT ANGER BUBBLE;So;0;ON;;;;;N;;;;; +1F5EF;RIGHT ANGER BUBBLE;So;0;ON;;;;;N;;;;; +1F5F0;MOOD BUBBLE;So;0;ON;;;;;N;;;;; +1F5F1;LIGHTNING MOOD BUBBLE;So;0;ON;;;;;N;;;;; +1F5F2;LIGHTNING MOOD;So;0;ON;;;;;N;;;;; +1F5F3;BALLOT BOX WITH BALLOT;So;0;ON;;;;;N;;;;; +1F5F4;BALLOT SCRIPT X;So;0;ON;;;;;N;;;;; +1F5F5;BALLOT BOX WITH SCRIPT X;So;0;ON;;;;;N;;;;; +1F5F6;BALLOT BOLD SCRIPT X;So;0;ON;;;;;N;;;;; +1F5F7;BALLOT BOX WITH BOLD SCRIPT X;So;0;ON;;;;;N;;;;; +1F5F8;LIGHT CHECK MARK;So;0;ON;;;;;N;;;;; +1F5F9;BALLOT BOX WITH BOLD CHECK;So;0;ON;;;;;N;;;;; +1F5FA;WORLD MAP;So;0;ON;;;;;N;;;;; 1F5FB;MOUNT FUJI;So;0;ON;;;;;N;;;;; 1F5FC;TOKYO TOWER;So;0;ON;;;;;N;;;;; 1F5FD;STATUE OF LIBERTY;So;0;ON;;;;;N;;;;; @@ -23341,6 +25870,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F63E;POUTING CAT FACE;So;0;ON;;;;;N;;;;; 1F63F;CRYING CAT FACE;So;0;ON;;;;;N;;;;; 1F640;WEARY CAT FACE;So;0;ON;;;;;N;;;;; +1F641;SLIGHTLY FROWNING FACE;So;0;ON;;;;;N;;;;; +1F642;SLIGHTLY SMILING FACE;So;0;ON;;;;;N;;;;; 1F645;FACE WITH NO GOOD GESTURE;So;0;ON;;;;;N;;;;; 1F646;FACE WITH OK GESTURE;So;0;ON;;;;;N;;;;; 1F647;PERSON BOWING DEEPLY;So;0;ON;;;;;N;;;;; @@ -23352,6 +25883,54 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F64D;PERSON FROWNING;So;0;ON;;;;;N;;;;; 1F64E;PERSON WITH POUTING FACE;So;0;ON;;;;;N;;;;; 1F64F;PERSON WITH FOLDED HANDS;So;0;ON;;;;;N;;;;; +1F650;NORTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F651;SOUTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F652;NORTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F653;SOUTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F654;TURNED NORTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F655;TURNED SOUTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F656;TURNED NORTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F657;TURNED SOUTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;; +1F658;NORTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F659;SOUTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65A;NORTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65B;SOUTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65C;HEAVY NORTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65D;HEAVY SOUTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65E;HEAVY NORTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F65F;HEAVY SOUTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;; +1F660;NORTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; +1F661;SOUTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; +1F662;NORTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; +1F663;SOUTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; +1F664;HEAVY NORTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; +1F665;HEAVY SOUTH WEST POINTING BUD;So;0;ON;;;;;N;;;;; +1F666;HEAVY NORTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; +1F667;HEAVY SOUTH EAST POINTING BUD;So;0;ON;;;;;N;;;;; +1F668;HOLLOW QUILT SQUARE ORNAMENT;So;0;ON;;;;;N;;;;; +1F669;HOLLOW QUILT SQUARE ORNAMENT IN BLACK SQUARE;So;0;ON;;;;;N;;;;; +1F66A;SOLID QUILT SQUARE ORNAMENT;So;0;ON;;;;;N;;;;; +1F66B;SOLID QUILT SQUARE ORNAMENT IN BLACK SQUARE;So;0;ON;;;;;N;;;;; +1F66C;LEFTWARDS ROCKET;So;0;ON;;;;;N;;;;; +1F66D;UPWARDS ROCKET;So;0;ON;;;;;N;;;;; +1F66E;RIGHTWARDS ROCKET;So;0;ON;;;;;N;;;;; +1F66F;DOWNWARDS ROCKET;So;0;ON;;;;;N;;;;; +1F670;SCRIPT LIGATURE ET ORNAMENT;So;0;ON;;;;;N;;;;; +1F671;HEAVY SCRIPT LIGATURE ET ORNAMENT;So;0;ON;;;;;N;;;;; +1F672;LIGATURE OPEN ET ORNAMENT;So;0;ON;;;;;N;;;;; +1F673;HEAVY LIGATURE OPEN ET ORNAMENT;So;0;ON;;;;;N;;;;; +1F674;HEAVY AMPERSAND ORNAMENT;So;0;ON;;;;;N;;;;; +1F675;SWASH AMPERSAND ORNAMENT;So;0;ON;;;;;N;;;;; +1F676;SANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +1F677;SANS-SERIF HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +1F678;SANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +1F679;HEAVY INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;; +1F67A;SANS-SERIF INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;; +1F67B;HEAVY SANS-SERIF INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;; +1F67C;VERY HEAVY SOLIDUS;So;0;ON;;;;;N;;;;; +1F67D;VERY HEAVY REVERSE SOLIDUS;So;0;ON;;;;;N;;;;; +1F67E;CHECKER BOARD;So;0;ON;;;;;N;;;;; +1F67F;REVERSE CHECKER BOARD;So;0;ON;;;;;N;;;;; 1F680;ROCKET;So;0;ON;;;;;N;;;;; 1F681;HELICOPTER;So;0;ON;;;;;N;;;;; 1F682;STEAM LOCOMOTIVE;So;0;ON;;;;;N;;;;; @@ -23422,6 +26001,33 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F6C3;CUSTOMS;So;0;ON;;;;;N;;;;; 1F6C4;BAGGAGE CLAIM;So;0;ON;;;;;N;;;;; 1F6C5;LEFT LUGGAGE;So;0;ON;;;;;N;;;;; +1F6C6;TRIANGLE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;; +1F6C7;PROHIBITED SIGN;So;0;ON;;;;;N;;;;; +1F6C8;CIRCLED INFORMATION SOURCE;So;0;ON;;;;;N;;;;; +1F6C9;BOYS SYMBOL;So;0;ON;;;;;N;;;;; +1F6CA;GIRLS SYMBOL;So;0;ON;;;;;N;;;;; +1F6CB;COUCH AND LAMP;So;0;ON;;;;;N;;;;; +1F6CC;SLEEPING ACCOMMODATION;So;0;ON;;;;;N;;;;; +1F6CD;SHOPPING BAGS;So;0;ON;;;;;N;;;;; +1F6CE;BELLHOP BELL;So;0;ON;;;;;N;;;;; +1F6CF;BED;So;0;ON;;;;;N;;;;; +1F6E0;HAMMER AND WRENCH;So;0;ON;;;;;N;;;;; +1F6E1;SHIELD;So;0;ON;;;;;N;;;;; +1F6E2;OIL DRUM;So;0;ON;;;;;N;;;;; +1F6E3;MOTORWAY;So;0;ON;;;;;N;;;;; +1F6E4;RAILWAY TRACK;So;0;ON;;;;;N;;;;; +1F6E5;MOTOR BOAT;So;0;ON;;;;;N;;;;; +1F6E6;UP-POINTING MILITARY AIRPLANE;So;0;ON;;;;;N;;;;; +1F6E7;UP-POINTING AIRPLANE;So;0;ON;;;;;N;;;;; +1F6E8;UP-POINTING SMALL AIRPLANE;So;0;ON;;;;;N;;;;; +1F6E9;SMALL AIRPLANE;So;0;ON;;;;;N;;;;; +1F6EA;NORTHEAST-POINTING AIRPLANE;So;0;ON;;;;;N;;;;; +1F6EB;AIRPLANE DEPARTURE;So;0;ON;;;;;N;;;;; +1F6EC;AIRPLANE ARRIVING;So;0;ON;;;;;N;;;;; +1F6F0;SATELLITE;So;0;ON;;;;;N;;;;; +1F6F1;ONCOMING FIRE ENGINE;So;0;ON;;;;;N;;;;; +1F6F2;DIESEL LOCOMOTIVE;So;0;ON;;;;;N;;;;; +1F6F3;PASSENGER SHIP;So;0;ON;;;;;N;;;;; 1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;; 1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;; 1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;; @@ -23538,6 +26144,239 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F771;ALCHEMICAL SYMBOL FOR MONTH;So;0;ON;;;;;N;;;;; 1F772;ALCHEMICAL SYMBOL FOR HALF DRAM;So;0;ON;;;;;N;;;;; 1F773;ALCHEMICAL SYMBOL FOR HALF OUNCE;So;0;ON;;;;;N;;;;; +1F780;BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +1F781;BLACK UP-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +1F782;BLACK RIGHT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +1F783;BLACK DOWN-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +1F784;BLACK SLIGHTLY SMALL CIRCLE;So;0;ON;;;;;N;;;;; +1F785;MEDIUM BOLD WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F786;BOLD WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F787;HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F788;VERY HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F789;EXTREMELY HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;; +1F78A;WHITE CIRCLE CONTAINING BLACK SMALL CIRCLE;So;0;ON;;;;;N;;;;; +1F78B;ROUND TARGET;So;0;ON;;;;;N;;;;; +1F78C;BLACK TINY SQUARE;So;0;ON;;;;;N;;;;; +1F78D;BLACK SLIGHTLY SMALL SQUARE;So;0;ON;;;;;N;;;;; +1F78E;LIGHT WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F78F;MEDIUM WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F790;BOLD WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F791;HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F792;VERY HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F793;EXTREMELY HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;; +1F794;WHITE SQUARE CONTAINING BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;; +1F795;WHITE SQUARE CONTAINING BLACK MEDIUM SQUARE;So;0;ON;;;;;N;;;;; +1F796;SQUARE TARGET;So;0;ON;;;;;N;;;;; +1F797;BLACK TINY DIAMOND;So;0;ON;;;;;N;;;;; +1F798;BLACK VERY SMALL DIAMOND;So;0;ON;;;;;N;;;;; +1F799;BLACK MEDIUM SMALL DIAMOND;So;0;ON;;;;;N;;;;; +1F79A;WHITE DIAMOND CONTAINING BLACK VERY SMALL DIAMOND;So;0;ON;;;;;N;;;;; +1F79B;WHITE DIAMOND CONTAINING BLACK MEDIUM DIAMOND;So;0;ON;;;;;N;;;;; +1F79C;DIAMOND TARGET;So;0;ON;;;;;N;;;;; +1F79D;BLACK TINY LOZENGE;So;0;ON;;;;;N;;;;; +1F79E;BLACK VERY SMALL LOZENGE;So;0;ON;;;;;N;;;;; +1F79F;BLACK MEDIUM SMALL LOZENGE;So;0;ON;;;;;N;;;;; +1F7A0;WHITE LOZENGE CONTAINING BLACK SMALL LOZENGE;So;0;ON;;;;;N;;;;; +1F7A1;THIN GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A2;LIGHT GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A3;MEDIUM GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A4;BOLD GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A5;VERY BOLD GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A6;VERY HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A7;EXTREMELY HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;; +1F7A8;THIN SALTIRE;So;0;ON;;;;;N;;;;; +1F7A9;LIGHT SALTIRE;So;0;ON;;;;;N;;;;; +1F7AA;MEDIUM SALTIRE;So;0;ON;;;;;N;;;;; +1F7AB;BOLD SALTIRE;So;0;ON;;;;;N;;;;; +1F7AC;HEAVY SALTIRE;So;0;ON;;;;;N;;;;; +1F7AD;VERY HEAVY SALTIRE;So;0;ON;;;;;N;;;;; +1F7AE;EXTREMELY HEAVY SALTIRE;So;0;ON;;;;;N;;;;; +1F7AF;LIGHT FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B0;MEDIUM FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B1;BOLD FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B2;HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B3;VERY HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B4;EXTREMELY HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B5;LIGHT SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B6;MEDIUM SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B7;BOLD SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B8;HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7B9;VERY HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BA;EXTREMELY HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BB;LIGHT EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BC;MEDIUM EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BD;BOLD EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BE;HEAVY EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7BF;VERY HEAVY EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +1F7C0;LIGHT THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C1;MEDIUM THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C2;THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C3;MEDIUM THREE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7C4;LIGHT FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C5;MEDIUM FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C6;FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7C7;MEDIUM FOUR POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7C8;REVERSE LIGHT FOUR POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7C9;LIGHT FIVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7CA;HEAVY FIVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7CB;MEDIUM SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7CC;HEAVY SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7CD;SIX POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7CE;MEDIUM EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7CF;HEAVY EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7D0;VERY HEAVY EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7D1;HEAVY EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F7D2;LIGHT TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7D3;HEAVY TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +1F7D4;HEAVY TWELVE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +1F800;LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F801;UPWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F802;RIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F803;DOWNWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F804;LEFTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F805;UPWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F806;RIGHTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F807;DOWNWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F808;LEFTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F809;UPWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F80A;RIGHTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F80B;DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F810;LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F811;UPWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F812;RIGHTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F813;DOWNWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F814;LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F815;UPWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F816;RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F817;DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F818;HEAVY LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F819;HEAVY UPWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81A;HEAVY RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81B;HEAVY DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81C;HEAVY LEFTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81D;HEAVY UPWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81E;HEAVY RIGHTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F81F;HEAVY DOWNWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;; +1F820;LEFTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; +1F821;UPWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; +1F822;RIGHTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; +1F823;DOWNWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;; +1F824;LEFTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; +1F825;UPWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; +1F826;RIGHTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; +1F827;DOWNWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;; +1F828;LEFTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; +1F829;UPWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; +1F82A;RIGHTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; +1F82B;DOWNWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;; +1F82C;LEFTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F82D;UPWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F82E;RIGHTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F82F;DOWNWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F830;LEFTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F831;UPWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F832;RIGHTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F833;DOWNWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;; +1F834;LEFTWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; +1F835;UPWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; +1F836;RIGHTWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; +1F837;DOWNWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;; +1F838;LEFTWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; +1F839;UPWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; +1F83A;RIGHTWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; +1F83B;DOWNWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;; +1F83C;LEFTWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F83D;UPWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F83E;RIGHTWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F83F;DOWNWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F840;LEFTWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F841;UPWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F842;RIGHTWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F843;DOWNWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;; +1F844;LEFTWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; +1F845;UPWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; +1F846;RIGHTWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; +1F847;DOWNWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;; +1F850;LEFTWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F851;UPWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F852;RIGHTWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F853;DOWNWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F854;NORTH WEST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F855;NORTH EAST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F856;SOUTH EAST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F857;SOUTH WEST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F858;LEFT RIGHT SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F859;UP DOWN SANS-SERIF ARROW;So;0;ON;;;;;N;;;;; +1F860;WIDE-HEADED LEFTWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F861;WIDE-HEADED UPWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F862;WIDE-HEADED RIGHTWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F863;WIDE-HEADED DOWNWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F864;WIDE-HEADED NORTH WEST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F865;WIDE-HEADED NORTH EAST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F866;WIDE-HEADED SOUTH EAST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F867;WIDE-HEADED SOUTH WEST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;; +1F868;WIDE-HEADED LEFTWARDS BARB ARROW;So;0;ON;;;;;N;;;;; +1F869;WIDE-HEADED UPWARDS BARB ARROW;So;0;ON;;;;;N;;;;; +1F86A;WIDE-HEADED RIGHTWARDS BARB ARROW;So;0;ON;;;;;N;;;;; +1F86B;WIDE-HEADED DOWNWARDS BARB ARROW;So;0;ON;;;;;N;;;;; +1F86C;WIDE-HEADED NORTH WEST BARB ARROW;So;0;ON;;;;;N;;;;; +1F86D;WIDE-HEADED NORTH EAST BARB ARROW;So;0;ON;;;;;N;;;;; +1F86E;WIDE-HEADED SOUTH EAST BARB ARROW;So;0;ON;;;;;N;;;;; +1F86F;WIDE-HEADED SOUTH WEST BARB ARROW;So;0;ON;;;;;N;;;;; +1F870;WIDE-HEADED LEFTWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F871;WIDE-HEADED UPWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F872;WIDE-HEADED RIGHTWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F873;WIDE-HEADED DOWNWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F874;WIDE-HEADED NORTH WEST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F875;WIDE-HEADED NORTH EAST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F876;WIDE-HEADED SOUTH EAST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F877;WIDE-HEADED SOUTH WEST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;; +1F878;WIDE-HEADED LEFTWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F879;WIDE-HEADED UPWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87A;WIDE-HEADED RIGHTWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87B;WIDE-HEADED DOWNWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87C;WIDE-HEADED NORTH WEST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87D;WIDE-HEADED NORTH EAST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87E;WIDE-HEADED SOUTH EAST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F87F;WIDE-HEADED SOUTH WEST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F880;WIDE-HEADED LEFTWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F881;WIDE-HEADED UPWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F882;WIDE-HEADED RIGHTWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F883;WIDE-HEADED DOWNWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F884;WIDE-HEADED NORTH WEST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F885;WIDE-HEADED NORTH EAST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F886;WIDE-HEADED SOUTH EAST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F887;WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;; +1F890;LEFTWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F891;UPWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F892;RIGHTWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F893;DOWNWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F894;LEFTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F895;UPWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F896;RIGHTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F897;DOWNWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; +1F898;LEFTWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; +1F899;UPWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; +1F89A;RIGHTWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; +1F89B;DOWNWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;; +1F89C;HEAVY ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;; +1F89D;HEAVY ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;; +1F89E;HEAVY ARROW SHAFT WIDTH ONE HALF;So;0;ON;;;;;N;;;;; +1F89F;HEAVY ARROW SHAFT WIDTH ONE THIRD;So;0;ON;;;;;N;;;;; +1F8A0;LEFTWARDS BOTTOM-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A1;RIGHTWARDS BOTTOM SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A2;LEFTWARDS TOP SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A3;RIGHTWARDS TOP SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A4;LEFTWARDS LEFT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A5;RIGHTWARDS RIGHT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A6;LEFTWARDS RIGHT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A7;RIGHTWARDS LEFT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A8;LEFTWARDS BACK-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8A9;RIGHTWARDS BACK-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8AA;LEFTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8AB;RIGHTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; +1F8AC;WHITE ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;; +1F8AD;WHITE ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;; 20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;; 2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;; 2A700;<CJK Ideograph Extension C, First>;Lo;0;L;;;;;N;;;;; diff --git a/jdk/make/data/unicodedata/VERSION b/jdk/make/data/unicodedata/VERSION index 6abaeb2f907..66ce77b7ead 100644 --- a/jdk/make/data/unicodedata/VERSION +++ b/jdk/make/data/unicodedata/VERSION @@ -1 +1 @@ -6.2.0 +7.0.0 diff --git a/jdk/make/src/classes/build/tools/generatecharacter/GenerateCharacter.java b/jdk/make/src/classes/build/tools/generatecharacter/GenerateCharacter.java index 83973ef07c4..58e9dc74fd7 100644 --- a/jdk/make/src/classes/build/tools/generatecharacter/GenerateCharacter.java +++ b/jdk/make/src/classes/build/tools/generatecharacter/GenerateCharacter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -906,6 +906,14 @@ OUTER: for (int i = 0; i < n; i += m) { return Integer.toString(UnicodeSpec.DIRECTIONALITY_WHITESPACE); if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS][UnicodeSpec.LONG])) return Integer.toString(UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_FIRST_STRONG_ISOLATE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_FIRST_STRONG_ISOLATE); + if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE][UnicodeSpec.LONG])) + return Integer.toString(UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE); FAIL("Unknown text substitution marker " + commandMarker + x); return commandMarker + x; } diff --git a/jdk/make/src/classes/build/tools/generatecharacter/UnicodeSpec.java b/jdk/make/src/classes/build/tools/generatecharacter/UnicodeSpec.java index 569fd29c467..7946117d0d3 100644 --- a/jdk/make/src/classes/build/tools/generatecharacter/UnicodeSpec.java +++ b/jdk/make/src/classes/build/tools/generatecharacter/UnicodeSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,7 +121,7 @@ public class UnicodeSpec { String[] tokens = null; try { - tokens = tokenSeparator.split(s, REQUIRED_FIELDS); + tokens = tokenSeparator.split(s, REQUIRED_FIELDS); spec = new UnicodeSpec(); spec.setCodePoint(parseCodePoint(tokens[FIELD_VALUE])); spec.setName(parseName(tokens[FIELD_NAME])); @@ -672,7 +672,8 @@ public class UnicodeSpec { * Bidirectional categories */ public static final byte - DIRECTIONALITY_UNDEFINED = -1, + DIRECTIONALITY_UNDEFINED = -1, + // Strong category DIRECTIONALITY_LEFT_TO_RIGHT = 0, // L DIRECTIONALITY_RIGHT_TO_LEFT = 1, // R @@ -689,15 +690,19 @@ public class UnicodeSpec { DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10, // B DIRECTIONALITY_SEGMENT_SEPARATOR = 11, // S DIRECTIONALITY_WHITESPACE = 12, // WS - DIRECTIONALITY_OTHER_NEUTRALS = 13, // ON - + DIRECTIONALITY_OTHER_NEUTRALS = 13, // ON + // Explicit Formatting category DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14, // LRE DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15, // LRO DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16, // RLE DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17, // RLO DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18, // PDF + DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE = 19, // LRI + DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE = 20, // RLI + DIRECTIONALITY_FIRST_STRONG_ISOLATE = 21, // FSI + DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE = 22, // PDI - DIRECTIONALITY_CATEGORY_COUNT = 19; // sentinel value + DIRECTIONALITY_CATEGORY_COUNT = 23; // sentinel value // If changes are made to the above bidi category assignments, this // list of bidi category names must be changed to keep their order in synch. @@ -722,7 +727,10 @@ public class UnicodeSpec { {"RLE", "DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING"}, {"RLO", "DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE"}, {"PDF", "DIRECTIONALITY_POP_DIRECTIONAL_FORMAT"}, - + {"LRI", "DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE"}, + {"RLI", "DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE"}, + {"FSI", "DIRECTIONALITY_FIRST_STRONG_ISOLATE"}, + {"PDI", "DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE"}, }; // Unicode specification lines have fields in this order. diff --git a/jdk/src/java.base/share/classes/java/lang/Character.java b/jdk/src/java.base/share/classes/java/lang/Character.java index 6dd68aa9cb1..a4e806876dc 100644 --- a/jdk/src/java.base/share/classes/java/lang/Character.java +++ b/jdk/src/java.base/share/classes/java/lang/Character.java @@ -42,7 +42,7 @@ import jdk.internal.HotSpotIntrinsicCandidate; * a character's category (lowercase letter, digit, etc.) and for converting * characters from uppercase to lowercase and vice versa. * <p> - * Character information is based on the Unicode Standard, version 6.2.0. + * Character information is based on the Unicode Standard, version 7.0.0. * <p> * The methods and data of class {@code Character} are defined by * the information in the <i>UnicodeData</i> file that is part of the @@ -491,6 +491,30 @@ class Character implements java.io.Serializable, Comparable<Character> { */ public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18; + /** + * Weak bidirectional character type "LRI" in the Unicode specification. + * @since 1.9 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE = 19; + + /** + * Weak bidirectional character type "RLI" in the Unicode specification. + * @since 1.9 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE = 20; + + /** + * Weak bidirectional character type "FSI" in the Unicode specification. + * @since 1.9 + */ + public static final byte DIRECTIONALITY_FIRST_STRONG_ISOLATE = 21; + + /** + * Weak bidirectional character type "PDI" in the Unicode specification. + * @since 1.9 + */ + public static final byte DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE = 22; + /** * The minimum value of a * <a href="http://www.unicode.org/glossary/#high_surrogate_code_unit"> @@ -2563,6 +2587,269 @@ class Character implements java.io.Serializable, Comparable<Character> { "ARABIC MATHEMATICAL ALPHABETIC SYMBOLS", "ARABICMATHEMATICALALPHABETICSYMBOLS"); + /** + * Constant for the "Combining Diacritical Marks Extended" Unicode + * character block. + * @since 1.9 + */ + public static final UnicodeBlock COMBINING_DIACRITICAL_MARKS_EXTENDED = + new UnicodeBlock("COMBINING_DIACRITICAL_MARKS_EXTENDED", + "COMBINING DIACRITICAL MARKS EXTENDED", + "COMBININGDIACRITICALMARKSEXTENDED"); + + /** + * Constant for the "Myanmar Extended-B" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock MYANMAR_EXTENDED_B = + new UnicodeBlock("MYANMAR_EXTENDED_B", + "MYANMAR EXTENDED-B", + "MYANMAREXTENDED-B"); + + /** + * Constant for the "Latin Extended-E" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock LATIN_EXTENDED_E = + new UnicodeBlock("LATIN_EXTENDED_E", + "LATIN EXTENDED-E", + "LATINEXTENDED-E"); + + /** + * Constant for the "Coptic Epact Numbers" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock COPTIC_EPACT_NUMBERS = + new UnicodeBlock("COPTIC_EPACT_NUMBERS", + "COPTIC EPACT NUMBERS", + "COPTICEPACTNUMBERS"); + + /** + * Constant for the "Old Permic" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock OLD_PERMIC = + new UnicodeBlock("OLD_PERMIC", + "OLD PERMIC", + "OLDPERMIC"); + + /** + * Constant for the "Elbasan" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock ELBASAN = + new UnicodeBlock("ELBASAN"); + + /** + * Constant for the "Caucasian Albanian" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock CAUCASIAN_ALBANIAN = + new UnicodeBlock("CAUCASIAN_ALBANIAN", + "CAUCASIAN ALBANIAN", + "CAUCASIANALBANIAN"); + + /** + * Constant for the "Linear A" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock LINEAR_A = + new UnicodeBlock("LINEAR_A", + "LINEAR A", + "LINEARA"); + + /** + * Constant for the "Palmyrene" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock PALMYRENE = + new UnicodeBlock("PALMYRENE"); + + /** + * Constant for the "Nabataean" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock NABATAEAN = + new UnicodeBlock("NABATAEAN"); + + /** + * Constant for the "Old North Arabian" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock OLD_NORTH_ARABIAN = + new UnicodeBlock("OLD_NORTH_ARABIAN", + "OLD NORTH ARABIAN", + "OLDNORTHARABIAN"); + + /** + * Constant for the "Manichaean" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock MANICHAEAN = + new UnicodeBlock("MANICHAEAN"); + + /** + * Constant for the "Psalter Pahlavi" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock PSALTER_PAHLAVI = + new UnicodeBlock("PSALTER_PAHLAVI", + "PSALTER PAHLAVI", + "PSALTERPAHLAVI"); + + /** + * Constant for the "Mahajani" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock MAHAJANI = + new UnicodeBlock("MAHAJANI"); + + /** + * Constant for the "Sinhala Archaic Numbers" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock SINHALA_ARCHAIC_NUMBERS = + new UnicodeBlock("SINHALA_ARCHAIC_NUMBERS", + "SINHALA ARCHAIC NUMBERS", + "SINHALAARCHAICNUMBERS"); + + /** + * Constant for the "Khojki" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock KHOJKI = + new UnicodeBlock("KHOJKI"); + + /** + * Constant for the "Khudawadi" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock KHUDAWADI = + new UnicodeBlock("KHUDAWADI"); + + /** + * Constant for the "Grantha" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock GRANTHA = + new UnicodeBlock("GRANTHA"); + + /** + * Constant for the "Tirhuta" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock TIRHUTA = + new UnicodeBlock("TIRHUTA"); + + /** + * Constant for the "Siddham" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock SIDDHAM = + new UnicodeBlock("SIDDHAM"); + + /** + * Constant for the "Modi" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock MODI = + new UnicodeBlock("MODI"); + + /** + * Constant for the "Warang Citi" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock WARANG_CITI = + new UnicodeBlock("WARANG_CITI", + "WARANG CITI", + "WARANGCITI"); + + /** + * Constant for the "Pau Cin Hau" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock PAU_CIN_HAU = + new UnicodeBlock("PAU_CIN_HAU", + "PAU CIN HAU", + "PAUCINHAU"); + + /** + * Constant for the "Mro" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock MRO = + new UnicodeBlock("MRO"); + + /** + * Constant for the "Bassa Vah" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock BASSA_VAH = + new UnicodeBlock("BASSA_VAH", + "BASSA VAH", + "BASSAVAH"); + + /** + * Constant for the "Pahawh Hmong" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock PAHAWH_HMONG = + new UnicodeBlock("PAHAWH_HMONG", + "PAHAWH HMONG", + "PAHAWHHMONG"); + + /** + * Constant for the "Duployan" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock DUPLOYAN = + new UnicodeBlock("DUPLOYAN"); + + /** + * Constant for the "Shorthand Format Controls" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock SHORTHAND_FORMAT_CONTROLS = + new UnicodeBlock("SHORTHAND_FORMAT_CONTROLS", + "SHORTHAND FORMAT CONTROLS", + "SHORTHANDFORMATCONTROLS"); + + /** + * Constant for the "Mende Kikakui" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock MENDE_KIKAKUI = + new UnicodeBlock("MENDE_KIKAKUI", + "MENDE KIKAKUI", + "MENDEKIKAKUI"); + + /** + * Constant for the "Ornamental Dingbats" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock ORNAMENTAL_DINGBATS = + new UnicodeBlock("ORNAMENTAL_DINGBATS", + "ORNAMENTAL DINGBATS", + "ORNAMENTALDINGBATS"); + + /** + * Constant for the "Geometric Shapes Extended" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock GEOMETRIC_SHAPES_EXTENDED = + new UnicodeBlock("GEOMETRIC_SHAPES_EXTENDED", + "GEOMETRIC SHAPES EXTENDED", + "GEOMETRICSHAPESEXTENDED"); + + /** + * Constant for the "Supplemental Arrows-C" Unicode character block. + * @since 1.9 + */ + public static final UnicodeBlock SUPPLEMENTAL_ARROWS_C = + new UnicodeBlock("SUPPLEMENTAL_ARROWS_C", + "SUPPLEMENTAL ARROWS-C", + "SUPPLEMENTALARROWS-C"); + private static final int blockStarts[] = { 0x0000, // 0000..007F; Basic Latin 0x0080, // 0080..00FF; Latin-1 Supplement @@ -2620,7 +2907,7 @@ class Character implements java.io.Serializable, Comparable<Character> { 0x19E0, // 19E0..19FF; Khmer Symbols 0x1A00, // 1A00..1A1F; Buginese 0x1A20, // 1A20..1AAF; Tai Tham - 0x1AB0, // unassigned + 0x1AB0, // 1AB0..1AFF; Combining Diacritical Marks Extended 0x1B00, // 1B00..1B7F; Balinese 0x1B80, // 1B80..1BBF; Sundanese 0x1BC0, // 1BC0..1BFF; Batak @@ -2701,13 +2988,14 @@ class Character implements java.io.Serializable, Comparable<Character> { 0xA930, // A930..A95F; Rejang 0xA960, // A960..A97F; Hangul Jamo Extended-A 0xA980, // A980..A9DF; Javanese - 0xA9E0, // unassigned + 0xA9E0, // A9E0..A9FF; Myanmar Extended-B 0xAA00, // AA00..AA5F; Cham 0xAA60, // AA60..AA7F; Myanmar Extended-A 0xAA80, // AA80..AADF; Tai Viet 0xAAE0, // AAE0..AAFF; Meetei Mayek Extensions 0xAB00, // AB00..AB2F; Ethiopic Extended-A - 0xAB30, // unassigned + 0xAB30, // AB30..AB6F; Latin Extended-E + 0xAB70, // unassigned 0xABC0, // ABC0..ABFF; Meetei Mayek 0xAC00, // AC00..D7AF; Hangul Syllables 0xD7B0, // D7B0..D7FF; Hangul Jamo Extended-B @@ -2735,10 +3023,10 @@ class Character implements java.io.Serializable, Comparable<Character> { 0x10200, // unassigned 0x10280, // 10280..1029F; Lycian 0x102A0, // 102A0..102DF; Carian - 0x102E0, // unassigned + 0x102E0, // 102E0..102FF; Coptic Epact Numbers 0x10300, // 10300..1032F; Old Italic 0x10330, // 10330..1034F; Gothic - 0x10350, // unassigned + 0x10350, // 10350..1037F; Old Permic 0x10380, // 10380..1039F; Ugaritic 0x103A0, // 103A0..103DF; Old Persian 0x103E0, // unassigned @@ -2746,9 +3034,16 @@ class Character implements java.io.Serializable, Comparable<Character> { 0x10450, // 10450..1047F; Shavian 0x10480, // 10480..104AF; Osmanya 0x104B0, // unassigned + 0x10500, // 10500..1052F; Elbasan + 0x10530, // 10530..1056F; Caucasian Albanian + 0x10570, // unassigned + 0x10600, // 10600..1077F; Linear A + 0x10780, // unassigned 0x10800, // 10800..1083F; Cypriot Syllabary 0x10840, // 10840..1085F; Imperial Aramaic - 0x10860, // unassigned + 0x10860, // 10860..1087F; Palmyrene + 0x10880, // 10880..108AF; Nabataean + 0x108B0, // unassigned 0x10900, // 10900..1091F; Phoenician 0x10920, // 10920..1093F; Lydian 0x10940, // unassigned @@ -2756,11 +3051,14 @@ class Character implements java.io.Serializable, Comparable<Character> { 0x109A0, // 109A0..109FF; Meroitic Cursive 0x10A00, // 10A00..10A5F; Kharoshthi 0x10A60, // 10A60..10A7F; Old South Arabian - 0x10A80, // unassigned + 0x10A80, // 10A80..10A9F; Old North Arabian + 0x10AA0, // unassigned + 0x10AC0, // 10AC0..10AFF; Manichaean 0x10B00, // 10B00..10B3F; Avestan 0x10B40, // 10B40..10B5F; Inscriptional Parthian 0x10B60, // 10B60..10B7F; Inscriptional Pahlavi - 0x10B80, // unassigned + 0x10B80, // 10B80..10BAF; Psalter Pahlavi + 0x10BB0, // unassigned 0x10C00, // 10C00..10C4F; Old Turkic 0x10C50, // unassigned 0x10E60, // 10E60..10E7F; Rumi Numeral Symbols @@ -2769,22 +3067,43 @@ class Character implements java.io.Serializable, Comparable<Character> { 0x11080, // 11080..110CF; Kaithi 0x110D0, // 110D0..110FF; Sora Sompeng 0x11100, // 11100..1114F; Chakma - 0x11150, // unassigned + 0x11150, // 11150..1117F; Mahajani 0x11180, // 11180..111DF; Sharada - 0x111E0, // unassigned + 0x111E0, // 111E0..111FF; Sinhala Archaic Numbers + 0x11200, // 11200..1124F; Khojki + 0x11250, // unassigned + 0x112B0, // 112B0..112FF; Khudawadi + 0x11300, // 11300..1137F; Grantha + 0x11380, // unassigned + 0x11480, // 11480..114DF; Tirhuta + 0x114E0, // unassigned + 0x11580, // 11580..115FF; Siddham + 0x11600, // 11600..1165F; Modi + 0x11660, // unassigned 0x11680, // 11680..116CF; Takri 0x116D0, // unassigned + 0x118A0, // 118A0..118FF; Warang Citi + 0x11900, // unassigned + 0x11AC0, // 11AC0..11AFF; Pau Cin Hau + 0x11B00, // unassigned 0x12000, // 12000..123FF; Cuneiform 0x12400, // 12400..1247F; Cuneiform Numbers and Punctuation 0x12480, // unassigned 0x13000, // 13000..1342F; Egyptian Hieroglyphs 0x13430, // unassigned 0x16800, // 16800..16A3F; Bamum Supplement - 0x16A40, // unassigned + 0x16A40, // 16A40..16A6F; Mro + 0x16A70, // unassigned + 0x16AD0, // 16AD0..16AFF; Bassa Vah + 0x16B00, // 16B00..16B8F; Pahawh Hmong + 0x16B90, // unassigned 0x16F00, // 16F00..16F9F; Miao 0x16FA0, // unassigned 0x1B000, // 1B000..1B0FF; Kana Supplement 0x1B100, // unassigned + 0x1BC00, // 1BC00..1BC9F; Duployan + 0x1BCA0, // 1BCA0..1BCAF; Shorthand Format Controls + 0x1BCB0, // unassigned 0x1D000, // 1D000..1D0FF; Byzantine Musical Symbols 0x1D100, // 1D100..1D1FF; Musical Symbols 0x1D200, // 1D200..1D24F; Ancient Greek Musical Notation @@ -2794,6 +3113,8 @@ class Character implements java.io.Serializable, Comparable<Character> { 0x1D380, // unassigned 0x1D400, // 1D400..1D7FF; Mathematical Alphanumeric Symbols 0x1D800, // unassigned + 0x1E800, // 1E800..1E8DF; Mende Kikakui + 0x1E8E0, // unassigned 0x1EE00, // 1EE00..1EEFF; Arabic Mathematical Alphabetic Symbols 0x1EF00, // unassigned 0x1F000, // 1F000..1F02F; Mahjong Tiles @@ -2803,10 +3124,12 @@ class Character implements java.io.Serializable, Comparable<Character> { 0x1F200, // 1F200..1F2FF; Enclosed Ideographic Supplement 0x1F300, // 1F300..1F5FF; Miscellaneous Symbols And Pictographs 0x1F600, // 1F600..1F64F; Emoticons - 0x1F650, // unassigned + 0x1F650, // 1F650..1F67F; Ornamental Dingbats 0x1F680, // 1F680..1F6FF; Transport And Map Symbols 0x1F700, // 1F700..1F77F; Alchemical Symbols - 0x1F780, // unassigned + 0x1F780, // 1F780..1F7FF; Geometric Shapes Extended + 0x1F800, // 1F800..1F8FF; Supplemental Arrows-C + 0x1F900, // unassigned 0x20000, // 20000..2A6DF; CJK Unified Ideographs Extension B 0x2A6E0, // unassigned 0x2A700, // 2A700..2B73F; CJK Unified Ideographs Extension C @@ -2879,7 +3202,7 @@ class Character implements java.io.Serializable, Comparable<Character> { KHMER_SYMBOLS, BUGINESE, TAI_THAM, - null, + COMBINING_DIACRITICAL_MARKS_EXTENDED, BALINESE, SUNDANESE, BATAK, @@ -2960,12 +3283,13 @@ class Character implements java.io.Serializable, Comparable<Character> { REJANG, HANGUL_JAMO_EXTENDED_A, JAVANESE, - null, + MYANMAR_EXTENDED_B, CHAM, MYANMAR_EXTENDED_A, TAI_VIET, MEETEI_MAYEK_EXTENSIONS, ETHIOPIC_EXTENDED_A, + LATIN_EXTENDED_E, null, MEETEI_MAYEK, HANGUL_SYLLABLES, @@ -2994,10 +3318,10 @@ class Character implements java.io.Serializable, Comparable<Character> { null, LYCIAN, CARIAN, - null, + COPTIC_EPACT_NUMBERS, OLD_ITALIC, GOTHIC, - null, + OLD_PERMIC, UGARITIC, OLD_PERSIAN, null, @@ -3005,8 +3329,15 @@ class Character implements java.io.Serializable, Comparable<Character> { SHAVIAN, OSMANYA, null, + ELBASAN, + CAUCASIAN_ALBANIAN, + null, + LINEAR_A, + null, CYPRIOT_SYLLABARY, IMPERIAL_ARAMAIC, + PALMYRENE, + NABATAEAN, null, PHOENICIAN, LYDIAN, @@ -3015,10 +3346,13 @@ class Character implements java.io.Serializable, Comparable<Character> { MEROITIC_CURSIVE, KHAROSHTHI, OLD_SOUTH_ARABIAN, + OLD_NORTH_ARABIAN, null, + MANICHAEAN, AVESTAN, INSCRIPTIONAL_PARTHIAN, INSCRIPTIONAL_PAHLAVI, + PSALTER_PAHLAVI, null, OLD_TURKIC, null, @@ -3028,22 +3362,43 @@ class Character implements java.io.Serializable, Comparable<Character> { KAITHI, SORA_SOMPENG, CHAKMA, - null, + MAHAJANI, SHARADA, + SINHALA_ARCHAIC_NUMBERS, + KHOJKI, + null, + KHUDAWADI, + GRANTHA, + null, + TIRHUTA, + null, + SIDDHAM, + MODI, null, TAKRI, null, + WARANG_CITI, + null, + PAU_CIN_HAU, + null, CUNEIFORM, CUNEIFORM_NUMBERS_AND_PUNCTUATION, null, EGYPTIAN_HIEROGLYPHS, null, BAMUM_SUPPLEMENT, + MRO, + null, + BASSA_VAH, + PAHAWH_HMONG, null, MIAO, null, KANA_SUPPLEMENT, null, + DUPLOYAN, + SHORTHAND_FORMAT_CONTROLS, + null, BYZANTINE_MUSICAL_SYMBOLS, MUSICAL_SYMBOLS, ANCIENT_GREEK_MUSICAL_NOTATION, @@ -3053,6 +3408,8 @@ class Character implements java.io.Serializable, Comparable<Character> { null, MATHEMATICAL_ALPHANUMERIC_SYMBOLS, null, + MENDE_KIKAKUI, + null, ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS, null, MAHJONG_TILES, @@ -3062,9 +3419,11 @@ class Character implements java.io.Serializable, Comparable<Character> { ENCLOSED_IDEOGRAPHIC_SUPPLEMENT, MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS, EMOTICONS, - null, + ORNAMENTAL_DINGBATS, TRANSPORT_AND_MAP_SYMBOLS, ALCHEMICAL_SYMBOLS, + GEOMETRIC_SHAPES_EXTENDED, + SUPPLEMENTAL_ARROWS_C, null, CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B, null, @@ -3677,39 +4036,184 @@ class Character implements java.io.Serializable, Comparable<Character> { /** * Unicode script "Meroitic Hieroglyphs". + * @since 1.8 */ MEROITIC_HIEROGLYPHS, /** * Unicode script "Meroitic Cursive". + * @since 1.8 */ MEROITIC_CURSIVE, /** * Unicode script "Sora Sompeng". + * @since 1.8 */ SORA_SOMPENG, /** * Unicode script "Chakma". + * @since 1.8 */ CHAKMA, /** * Unicode script "Sharada". + * @since 1.8 */ SHARADA, /** * Unicode script "Takri". + * @since 1.8 */ TAKRI, /** * Unicode script "Miao". + * @since 1.8 */ MIAO, + /** + * Unicode script "Caucasian Albanian". + * @since 1.9 + */ + CAUCASIAN_ALBANIAN, + + /** + * Unicode script "Bassa Vah". + * @since 1.9 + */ + BASSA_VAH, + + /** + * Unicode script "Duployan". + * @since 1.9 + */ + DUPLOYAN, + + /** + * Unicode script "Elbasan". + * @since 1.9 + */ + ELBASAN, + + /** + * Unicode script "Grantha". + * @since 1.9 + */ + GRANTHA, + + /** + * Unicode script "Pahawh Hmong". + * @since 1.9 + */ + PAHAWH_HMONG, + + /** + * Unicode script "Khojki". + * @since 1.9 + */ + KHOJKI, + + /** + * Unicode script "Linear A". + * @since 1.9 + */ + LINEAR_A, + + /** + * Unicode script "Mahajani". + * @since 1.9 + */ + MAHAJANI, + + /** + * Unicode script "Manichaean". + * @since 1.9 + */ + MANICHAEAN, + + /** + * Unicode script "Mende Kikakui". + * @since 1.9 + */ + MENDE_KIKAKUI, + + /** + * Unicode script "Modi". + * @since 1.9 + */ + MODI, + + /** + * Unicode script "Mro". + * @since 1.9 + */ + MRO, + + /** + * Unicode script "Old North Arabian". + * @since 1.9 + */ + OLD_NORTH_ARABIAN, + + /** + * Unicode script "Nabataean". + * @since 1.9 + */ + NABATAEAN, + + /** + * Unicode script "Palmyrene". + * @since 1.9 + */ + PALMYRENE, + + /** + * Unicode script "Pau Cin Hau". + * @since 1.9 + */ + PAU_CIN_HAU, + + /** + * Unicode script "Old Permic". + * @since 1.9 + */ + OLD_PERMIC, + + /** + * Unicode script "Psalter Pahlavi". + * @since 1.9 + */ + PSALTER_PAHLAVI, + + /** + * Unicode script "Siddham". + * @since 1.9 + */ + SIDDHAM, + + /** + * Unicode script "Khudawadi". + * @since 1.9 + */ + KHUDAWADI, + + /** + * Unicode script "Tirhuta". + * @since 1.9 + */ + TIRHUTA, + + /** + * Unicode script "Warang Citi". + * @since 1.9 + */ + WARANG_CITI, + /** * Unicode script "Unknown". */ @@ -3721,14 +4225,14 @@ class Character implements java.io.Serializable, Comparable<Character> { 0x005B, // 005B..0060; COMMON 0x0061, // 0061..007A; LATIN 0x007B, // 007B..00A9; COMMON - 0x00AA, // 00AA..00AA; LATIN + 0x00AA, // 00AA ; LATIN 0x00AB, // 00AB..00B9; COMMON - 0x00BA, // 00BA..00BA; LATIN + 0x00BA, // 00BA ; LATIN 0x00BB, // 00BB..00BF; COMMON 0x00C0, // 00C0..00D6; LATIN - 0x00D7, // 00D7..00D7; COMMON + 0x00D7, // 00D7 ; COMMON 0x00D8, // 00D8..00F6; LATIN - 0x00F7, // 00F7..00F7; COMMON + 0x00F7, // 00F7 ; COMMON 0x00F8, // 00F8..02B8; LATIN 0x02B9, // 02B9..02DF; COMMON 0x02E0, // 02E0..02E4; LATIN @@ -3737,284 +4241,1178 @@ class Character implements java.io.Serializable, Comparable<Character> { 0x02EC, // 02EC..02FF; COMMON 0x0300, // 0300..036F; INHERITED 0x0370, // 0370..0373; GREEK - 0x0374, // 0374..0374; COMMON - 0x0375, // 0375..037D; GREEK - 0x037E, // 037E..0383; COMMON - 0x0384, // 0384..0384; GREEK - 0x0385, // 0385..0385; COMMON - 0x0386, // 0386..0386; GREEK - 0x0387, // 0387..0387; COMMON - 0x0388, // 0388..03E1; GREEK + 0x0374, // 0374 ; COMMON + 0x0375, // 0375..0377; GREEK + 0x0378, // 0378..0379; UNKNOWN + 0x037A, // 037A..037D; GREEK + 0x037E, // 037E ; COMMON + 0x037F, // 037F ; GREEK + 0x0380, // 0380..0383; UNKNOWN + 0x0384, // 0384 ; GREEK + 0x0385, // 0385 ; COMMON + 0x0386, // 0386 ; GREEK + 0x0387, // 0387 ; COMMON + 0x0388, // 0388..038A; GREEK + 0x038B, // 038B ; UNKNOWN + 0x038C, // 038C ; GREEK + 0x038D, // 038D ; UNKNOWN + 0x038E, // 038E..03A1; GREEK + 0x03A2, // 03A2 ; UNKNOWN + 0x03A3, // 03A3..03E1; GREEK 0x03E2, // 03E2..03EF; COPTIC 0x03F0, // 03F0..03FF; GREEK 0x0400, // 0400..0484; CYRILLIC 0x0485, // 0485..0486; INHERITED - 0x0487, // 0487..0530; CYRILLIC - 0x0531, // 0531..0588; ARMENIAN - 0x0589, // 0589..0589; COMMON - 0x058A, // 058A..0590; ARMENIAN - 0x0591, // 0591..05FF; HEBREW - 0x0600, // 0600..060B; ARABIC - 0x060C, // 060C..060C; COMMON + 0x0487, // 0487..052F; CYRILLIC + 0x0530, // 0530 ; UNKNOWN + 0x0531, // 0531..0556; ARMENIAN + 0x0557, // 0557..0558; UNKNOWN + 0x0559, // 0559..055F; ARMENIAN + 0x0560, // 0560 ; UNKNOWN + 0x0561, // 0561..0587; ARMENIAN + 0x0588, // 0588 ; UNKNOWN + 0x0589, // 0589 ; COMMON + 0x058A, // 058A ; ARMENIAN + 0x058B, // 058B..058C; UNKNOWN + 0x058D, // 058D..058F; ARMENIAN + 0x0590, // 0590 ; UNKNOWN + 0x0591, // 0591..05C7; HEBREW + 0x05C8, // 05C8..05CF; UNKNOWN + 0x05D0, // 05D0..05EA; HEBREW + 0x05EB, // 05EB..05EF; UNKNOWN + 0x05F0, // 05F0..05F4; HEBREW + 0x05F5, // 05F5..05FF; UNKNOWN + 0x0600, // 0600..0604; ARABIC + 0x0605, // 0605 ; COMMON + 0x0606, // 0606..060B; ARABIC + 0x060C, // 060C ; COMMON 0x060D, // 060D..061A; ARABIC - 0x061B, // 061B..061D; COMMON - 0x061E, // 061E..061E; ARABIC - 0x061F, // 061F..061F; COMMON + 0x061B, // 061B..061C; COMMON + 0x061D, // 061D ; UNKNOWN + 0x061E, // 061E ; ARABIC + 0x061F, // 061F ; COMMON 0x0620, // 0620..063F; ARABIC - 0x0640, // 0640..0640; COMMON + 0x0640, // 0640 ; COMMON 0x0641, // 0641..064A; ARABIC 0x064B, // 064B..0655; INHERITED 0x0656, // 0656..065F; ARABIC 0x0660, // 0660..0669; COMMON 0x066A, // 066A..066F; ARABIC - 0x0670, // 0670..0670; INHERITED + 0x0670, // 0670 ; INHERITED 0x0671, // 0671..06DC; ARABIC - 0x06DD, // 06DD..06DD; COMMON + 0x06DD, // 06DD ; COMMON 0x06DE, // 06DE..06FF; ARABIC - 0x0700, // 0700..074F; SYRIAC + 0x0700, // 0700..070D; SYRIAC + 0x070E, // 070E ; UNKNOWN + 0x070F, // 070F..074A; SYRIAC + 0x074B, // 074B..074C; UNKNOWN + 0x074D, // 074D..074F; SYRIAC 0x0750, // 0750..077F; ARABIC - 0x0780, // 0780..07BF; THAANA - 0x07C0, // 07C0..07FF; NKO - 0x0800, // 0800..083F; SAMARITAN - 0x0840, // 0840..089F; MANDAIC - 0x08A0, // 08A0..08FF; ARABIC + 0x0780, // 0780..07B1; THAANA + 0x07B2, // 07B2..07BF; UNKNOWN + 0x07C0, // 07C0..07FA; NKO + 0x07FB, // 07FB..07FF; UNKNOWN + 0x0800, // 0800..082D; SAMARITAN + 0x082E, // 082E..082F; UNKNOWN + 0x0830, // 0830..083E; SAMARITAN + 0x083F, // 083F ; UNKNOWN + 0x0840, // 0840..085B; MANDAIC + 0x085C, // 085C..085D; UNKNOWN + 0x085E, // 085E ; MANDAIC + 0x085F, // 085F..089F; UNKNOWN + 0x08A0, // 08A0..08B2; ARABIC + 0x08B3, // 08B3..08E3; UNKNOWN + 0x08E4, // 08E4..08FF; ARABIC 0x0900, // 0900..0950; DEVANAGARI 0x0951, // 0951..0952; INHERITED 0x0953, // 0953..0963; DEVANAGARI 0x0964, // 0964..0965; COMMON - 0x0966, // 0966..0980; DEVANAGARI - 0x0981, // 0981..0A00; BENGALI - 0x0A01, // 0A01..0A80; GURMUKHI - 0x0A81, // 0A81..0B00; GUJARATI - 0x0B01, // 0B01..0B81; ORIYA - 0x0B82, // 0B82..0C00; TAMIL - 0x0C01, // 0C01..0C81; TELUGU - 0x0C82, // 0C82..0CF0; KANNADA - 0x0D02, // 0D02..0D81; MALAYALAM - 0x0D82, // 0D82..0E00; SINHALA - 0x0E01, // 0E01..0E3E; THAI - 0x0E3F, // 0E3F..0E3F; COMMON - 0x0E40, // 0E40..0E80; THAI - 0x0E81, // 0E81..0EFF; LAO - 0x0F00, // 0F00..0FD4; TIBETAN + 0x0966, // 0966..097F; DEVANAGARI + 0x0980, // 0980..0983; BENGALI + 0x0984, // 0984 ; UNKNOWN + 0x0985, // 0985..098C; BENGALI + 0x098D, // 098D..098E; UNKNOWN + 0x098F, // 098F..0990; BENGALI + 0x0991, // 0991..0992; UNKNOWN + 0x0993, // 0993..09A8; BENGALI + 0x09A9, // 09A9 ; UNKNOWN + 0x09AA, // 09AA..09B0; BENGALI + 0x09B1, // 09B1 ; UNKNOWN + 0x09B2, // 09B2 ; BENGALI + 0x09B3, // 09B3..09B5; UNKNOWN + 0x09B6, // 09B6..09B9; BENGALI + 0x09BA, // 09BA..09BB; UNKNOWN + 0x09BC, // 09BC..09C4; BENGALI + 0x09C5, // 09C5..09C6; UNKNOWN + 0x09C7, // 09C7..09C8; BENGALI + 0x09C9, // 09C9..09CA; UNKNOWN + 0x09CB, // 09CB..09CE; BENGALI + 0x09CF, // 09CF..09D6; UNKNOWN + 0x09D7, // 09D7 ; BENGALI + 0x09D8, // 09D8..09DB; UNKNOWN + 0x09DC, // 09DC..09DD; BENGALI + 0x09DE, // 09DE ; UNKNOWN + 0x09DF, // 09DF..09E3; BENGALI + 0x09E4, // 09E4..09E5; UNKNOWN + 0x09E6, // 09E6..09FB; BENGALI + 0x09FC, // 09FC..0A00; UNKNOWN + 0x0A01, // 0A01..0A03; GURMUKHI + 0x0A04, // 0A04 ; UNKNOWN + 0x0A05, // 0A05..0A0A; GURMUKHI + 0x0A0B, // 0A0B..0A0E; UNKNOWN + 0x0A0F, // 0A0F..0A10; GURMUKHI + 0x0A11, // 0A11..0A12; UNKNOWN + 0x0A13, // 0A13..0A28; GURMUKHI + 0x0A29, // 0A29 ; UNKNOWN + 0x0A2A, // 0A2A..0A30; GURMUKHI + 0x0A31, // 0A31 ; UNKNOWN + 0x0A32, // 0A32..0A33; GURMUKHI + 0x0A34, // 0A34 ; UNKNOWN + 0x0A35, // 0A35..0A36; GURMUKHI + 0x0A37, // 0A37 ; UNKNOWN + 0x0A38, // 0A38..0A39; GURMUKHI + 0x0A3A, // 0A3A..0A3B; UNKNOWN + 0x0A3C, // 0A3C ; GURMUKHI + 0x0A3D, // 0A3D ; UNKNOWN + 0x0A3E, // 0A3E..0A42; GURMUKHI + 0x0A43, // 0A43..0A46; UNKNOWN + 0x0A47, // 0A47..0A48; GURMUKHI + 0x0A49, // 0A49..0A4A; UNKNOWN + 0x0A4B, // 0A4B..0A4D; GURMUKHI + 0x0A4E, // 0A4E..0A50; UNKNOWN + 0x0A51, // 0A51 ; GURMUKHI + 0x0A52, // 0A52..0A58; UNKNOWN + 0x0A59, // 0A59..0A5C; GURMUKHI + 0x0A5D, // 0A5D ; UNKNOWN + 0x0A5E, // 0A5E ; GURMUKHI + 0x0A5F, // 0A5F..0A65; UNKNOWN + 0x0A66, // 0A66..0A75; GURMUKHI + 0x0A76, // 0A76..0A80; UNKNOWN + 0x0A81, // 0A81..0A83; GUJARATI + 0x0A84, // 0A84 ; UNKNOWN + 0x0A85, // 0A85..0A8D; GUJARATI + 0x0A8E, // 0A8E ; UNKNOWN + 0x0A8F, // 0A8F..0A91; GUJARATI + 0x0A92, // 0A92 ; UNKNOWN + 0x0A93, // 0A93..0AA8; GUJARATI + 0x0AA9, // 0AA9 ; UNKNOWN + 0x0AAA, // 0AAA..0AB0; GUJARATI + 0x0AB1, // 0AB1 ; UNKNOWN + 0x0AB2, // 0AB2..0AB3; GUJARATI + 0x0AB4, // 0AB4 ; UNKNOWN + 0x0AB5, // 0AB5..0AB9; GUJARATI + 0x0ABA, // 0ABA..0ABB; UNKNOWN + 0x0ABC, // 0ABC..0AC5; GUJARATI + 0x0AC6, // 0AC6 ; UNKNOWN + 0x0AC7, // 0AC7..0AC9; GUJARATI + 0x0ACA, // 0ACA ; UNKNOWN + 0x0ACB, // 0ACB..0ACD; GUJARATI + 0x0ACE, // 0ACE..0ACF; UNKNOWN + 0x0AD0, // 0AD0 ; GUJARATI + 0x0AD1, // 0AD1..0ADF; UNKNOWN + 0x0AE0, // 0AE0..0AE3; GUJARATI + 0x0AE4, // 0AE4..0AE5; UNKNOWN + 0x0AE6, // 0AE6..0AF1; GUJARATI + 0x0AF2, // 0AF2..0B00; UNKNOWN + 0x0B01, // 0B01..0B03; ORIYA + 0x0B04, // 0B04 ; UNKNOWN + 0x0B05, // 0B05..0B0C; ORIYA + 0x0B0D, // 0B0D..0B0E; UNKNOWN + 0x0B0F, // 0B0F..0B10; ORIYA + 0x0B11, // 0B11..0B12; UNKNOWN + 0x0B13, // 0B13..0B28; ORIYA + 0x0B29, // 0B29 ; UNKNOWN + 0x0B2A, // 0B2A..0B30; ORIYA + 0x0B31, // 0B31 ; UNKNOWN + 0x0B32, // 0B32..0B33; ORIYA + 0x0B34, // 0B34 ; UNKNOWN + 0x0B35, // 0B35..0B39; ORIYA + 0x0B3A, // 0B3A..0B3B; UNKNOWN + 0x0B3C, // 0B3C..0B44; ORIYA + 0x0B45, // 0B45..0B46; UNKNOWN + 0x0B47, // 0B47..0B48; ORIYA + 0x0B49, // 0B49..0B4A; UNKNOWN + 0x0B4B, // 0B4B..0B4D; ORIYA + 0x0B4E, // 0B4E..0B55; UNKNOWN + 0x0B56, // 0B56..0B57; ORIYA + 0x0B58, // 0B58..0B5B; UNKNOWN + 0x0B5C, // 0B5C..0B5D; ORIYA + 0x0B5E, // 0B5E ; UNKNOWN + 0x0B5F, // 0B5F..0B63; ORIYA + 0x0B64, // 0B64..0B65; UNKNOWN + 0x0B66, // 0B66..0B77; ORIYA + 0x0B78, // 0B78..0B81; UNKNOWN + 0x0B82, // 0B82..0B83; TAMIL + 0x0B84, // 0B84 ; UNKNOWN + 0x0B85, // 0B85..0B8A; TAMIL + 0x0B8B, // 0B8B..0B8D; UNKNOWN + 0x0B8E, // 0B8E..0B90; TAMIL + 0x0B91, // 0B91 ; UNKNOWN + 0x0B92, // 0B92..0B95; TAMIL + 0x0B96, // 0B96..0B98; UNKNOWN + 0x0B99, // 0B99..0B9A; TAMIL + 0x0B9B, // 0B9B ; UNKNOWN + 0x0B9C, // 0B9C ; TAMIL + 0x0B9D, // 0B9D ; UNKNOWN + 0x0B9E, // 0B9E..0B9F; TAMIL + 0x0BA0, // 0BA0..0BA2; UNKNOWN + 0x0BA3, // 0BA3..0BA4; TAMIL + 0x0BA5, // 0BA5..0BA7; UNKNOWN + 0x0BA8, // 0BA8..0BAA; TAMIL + 0x0BAB, // 0BAB..0BAD; UNKNOWN + 0x0BAE, // 0BAE..0BB9; TAMIL + 0x0BBA, // 0BBA..0BBD; UNKNOWN + 0x0BBE, // 0BBE..0BC2; TAMIL + 0x0BC3, // 0BC3..0BC5; UNKNOWN + 0x0BC6, // 0BC6..0BC8; TAMIL + 0x0BC9, // 0BC9 ; UNKNOWN + 0x0BCA, // 0BCA..0BCD; TAMIL + 0x0BCE, // 0BCE..0BCF; UNKNOWN + 0x0BD0, // 0BD0 ; TAMIL + 0x0BD1, // 0BD1..0BD6; UNKNOWN + 0x0BD7, // 0BD7 ; TAMIL + 0x0BD8, // 0BD8..0BE5; UNKNOWN + 0x0BE6, // 0BE6..0BFA; TAMIL + 0x0BFB, // 0BFB..0BFF; UNKNOWN + 0x0C00, // 0C00..0C03; TELUGU + 0x0C04, // 0C04 ; UNKNOWN + 0x0C05, // 0C05..0C0C; TELUGU + 0x0C0D, // 0C0D ; UNKNOWN + 0x0C0E, // 0C0E..0C10; TELUGU + 0x0C11, // 0C11 ; UNKNOWN + 0x0C12, // 0C12..0C28; TELUGU + 0x0C29, // 0C29 ; UNKNOWN + 0x0C2A, // 0C2A..0C39; TELUGU + 0x0C3A, // 0C3A..0C3C; UNKNOWN + 0x0C3D, // 0C3D..0C44; TELUGU + 0x0C45, // 0C45 ; UNKNOWN + 0x0C46, // 0C46..0C48; TELUGU + 0x0C49, // 0C49 ; UNKNOWN + 0x0C4A, // 0C4A..0C4D; TELUGU + 0x0C4E, // 0C4E..0C54; UNKNOWN + 0x0C55, // 0C55..0C56; TELUGU + 0x0C57, // 0C57 ; UNKNOWN + 0x0C58, // 0C58..0C59; TELUGU + 0x0C5A, // 0C5A..0C5F; UNKNOWN + 0x0C60, // 0C60..0C63; TELUGU + 0x0C64, // 0C64..0C65; UNKNOWN + 0x0C66, // 0C66..0C6F; TELUGU + 0x0C70, // 0C70..0C77; UNKNOWN + 0x0C78, // 0C78..0C7F; TELUGU + 0x0C80, // 0C80 ; UNKNOWN + 0x0C81, // 0C81..0C83; KANNADA + 0x0C84, // 0C84 ; UNKNOWN + 0x0C85, // 0C85..0C8C; KANNADA + 0x0C8D, // 0C8D ; UNKNOWN + 0x0C8E, // 0C8E..0C90; KANNADA + 0x0C91, // 0C91 ; UNKNOWN + 0x0C92, // 0C92..0CA8; KANNADA + 0x0CA9, // 0CA9 ; UNKNOWN + 0x0CAA, // 0CAA..0CB3; KANNADA + 0x0CB4, // 0CB4 ; UNKNOWN + 0x0CB5, // 0CB5..0CB9; KANNADA + 0x0CBA, // 0CBA..0CBB; UNKNOWN + 0x0CBC, // 0CBC..0CC4; KANNADA + 0x0CC5, // 0CC5 ; UNKNOWN + 0x0CC6, // 0CC6..0CC8; KANNADA + 0x0CC9, // 0CC9 ; UNKNOWN + 0x0CCA, // 0CCA..0CCD; KANNADA + 0x0CCE, // 0CCE..0CD4; UNKNOWN + 0x0CD5, // 0CD5..0CD6; KANNADA + 0x0CD7, // 0CD7..0CDD; UNKNOWN + 0x0CDE, // 0CDE ; KANNADA + 0x0CDF, // 0CDF ; UNKNOWN + 0x0CE0, // 0CE0..0CE3; KANNADA + 0x0CE4, // 0CE4..0CE5; UNKNOWN + 0x0CE6, // 0CE6..0CEF; KANNADA + 0x0CF0, // 0CF0 ; UNKNOWN + 0x0CF1, // 0CF1..0CF2; KANNADA + 0x0CF3, // 0CF3..0D00; UNKNOWN + 0x0D01, // 0D01..0D03; MALAYALAM + 0x0D04, // 0D04 ; UNKNOWN + 0x0D05, // 0D05..0D0C; MALAYALAM + 0x0D0D, // 0D0D ; UNKNOWN + 0x0D0E, // 0D0E..0D10; MALAYALAM + 0x0D11, // 0D11 ; UNKNOWN + 0x0D12, // 0D12..0D3A; MALAYALAM + 0x0D3B, // 0D3B..0D3C; UNKNOWN + 0x0D3D, // 0D3D..0D44; MALAYALAM + 0x0D45, // 0D45 ; UNKNOWN + 0x0D46, // 0D46..0D48; MALAYALAM + 0x0D49, // 0D49 ; UNKNOWN + 0x0D4A, // 0D4A..0D4E; MALAYALAM + 0x0D4F, // 0D4F..0D56; UNKNOWN + 0x0D57, // 0D57 ; MALAYALAM + 0x0D58, // 0D58..0D5F; UNKNOWN + 0x0D60, // 0D60..0D63; MALAYALAM + 0x0D64, // 0D64..0D65; UNKNOWN + 0x0D66, // 0D66..0D75; MALAYALAM + 0x0D76, // 0D76..0D78; UNKNOWN + 0x0D79, // 0D79..0D7F; MALAYALAM + 0x0D80, // 0D80..0D81; UNKNOWN + 0x0D82, // 0D82..0D83; SINHALA + 0x0D84, // 0D84 ; UNKNOWN + 0x0D85, // 0D85..0D96; SINHALA + 0x0D97, // 0D97..0D99; UNKNOWN + 0x0D9A, // 0D9A..0DB1; SINHALA + 0x0DB2, // 0DB2 ; UNKNOWN + 0x0DB3, // 0DB3..0DBB; SINHALA + 0x0DBC, // 0DBC ; UNKNOWN + 0x0DBD, // 0DBD ; SINHALA + 0x0DBE, // 0DBE..0DBF; UNKNOWN + 0x0DC0, // 0DC0..0DC6; SINHALA + 0x0DC7, // 0DC7..0DC9; UNKNOWN + 0x0DCA, // 0DCA ; SINHALA + 0x0DCB, // 0DCB..0DCE; UNKNOWN + 0x0DCF, // 0DCF..0DD4; SINHALA + 0x0DD5, // 0DD5 ; UNKNOWN + 0x0DD6, // 0DD6 ; SINHALA + 0x0DD7, // 0DD7 ; UNKNOWN + 0x0DD8, // 0DD8..0DDF; SINHALA + 0x0DE0, // 0DE0..0DE5; UNKNOWN + 0x0DE6, // 0DE6..0DEF; SINHALA + 0x0DF0, // 0DF0..0DF1; UNKNOWN + 0x0DF2, // 0DF2..0DF4; SINHALA + 0x0DF5, // 0DF5..0E00; UNKNOWN + 0x0E01, // 0E01..0E3A; THAI + 0x0E3B, // 0E3B..0E3E; UNKNOWN + 0x0E3F, // 0E3F ; COMMON + 0x0E40, // 0E40..0E5B; THAI + 0x0E5C, // 0E5C..0E80; UNKNOWN + 0x0E81, // 0E81..0E82; LAO + 0x0E83, // 0E83 ; UNKNOWN + 0x0E84, // 0E84 ; LAO + 0x0E85, // 0E85..0E86; UNKNOWN + 0x0E87, // 0E87..0E88; LAO + 0x0E89, // 0E89 ; UNKNOWN + 0x0E8A, // 0E8A ; LAO + 0x0E8B, // 0E8B..0E8C; UNKNOWN + 0x0E8D, // 0E8D ; LAO + 0x0E8E, // 0E8E..0E93; UNKNOWN + 0x0E94, // 0E94..0E97; LAO + 0x0E98, // 0E98 ; UNKNOWN + 0x0E99, // 0E99..0E9F; LAO + 0x0EA0, // 0EA0 ; UNKNOWN + 0x0EA1, // 0EA1..0EA3; LAO + 0x0EA4, // 0EA4 ; UNKNOWN + 0x0EA5, // 0EA5 ; LAO + 0x0EA6, // 0EA6 ; UNKNOWN + 0x0EA7, // 0EA7 ; LAO + 0x0EA8, // 0EA8..0EA9; UNKNOWN + 0x0EAA, // 0EAA..0EAB; LAO + 0x0EAC, // 0EAC ; UNKNOWN + 0x0EAD, // 0EAD..0EB9; LAO + 0x0EBA, // 0EBA ; UNKNOWN + 0x0EBB, // 0EBB..0EBD; LAO + 0x0EBE, // 0EBE..0EBF; UNKNOWN + 0x0EC0, // 0EC0..0EC4; LAO + 0x0EC5, // 0EC5 ; UNKNOWN + 0x0EC6, // 0EC6 ; LAO + 0x0EC7, // 0EC7 ; UNKNOWN + 0x0EC8, // 0EC8..0ECD; LAO + 0x0ECE, // 0ECE..0ECF; UNKNOWN + 0x0ED0, // 0ED0..0ED9; LAO + 0x0EDA, // 0EDA..0EDB; UNKNOWN + 0x0EDC, // 0EDC..0EDF; LAO + 0x0EE0, // 0EE0..0EFF; UNKNOWN + 0x0F00, // 0F00..0F47; TIBETAN + 0x0F48, // 0F48 ; UNKNOWN + 0x0F49, // 0F49..0F6C; TIBETAN + 0x0F6D, // 0F6D..0F70; UNKNOWN + 0x0F71, // 0F71..0F97; TIBETAN + 0x0F98, // 0F98 ; UNKNOWN + 0x0F99, // 0F99..0FBC; TIBETAN + 0x0FBD, // 0FBD ; UNKNOWN + 0x0FBE, // 0FBE..0FCC; TIBETAN + 0x0FCD, // 0FCD ; UNKNOWN + 0x0FCE, // 0FCE..0FD4; TIBETAN 0x0FD5, // 0FD5..0FD8; COMMON - 0x0FD9, // 0FD9..0FFF; TIBETAN + 0x0FD9, // 0FD9..0FDA; TIBETAN + 0x0FDB, // 0FDB..FFF; UNKNOWN 0x1000, // 1000..109F; MYANMAR - 0x10A0, // 10A0..10FA; GEORGIAN - 0x10FB, // 10FB..10FB; COMMON + 0x10A0, // 10A0..10C5; GEORGIAN + 0x10C6, // 10C6 ; UNKNOWN + 0x10C7, // 10C7 ; GEORGIAN + 0x10C8, // 10C8..10CC; UNKNOWN + 0x10CD, // 10CD ; GEORGIAN + 0x10CE, // 10CE..10CF; UNKNOWN + 0x10D0, // 10D0..10FA; GEORGIAN + 0x10FB, // 10FB ; COMMON 0x10FC, // 10FC..10FF; GEORGIAN 0x1100, // 1100..11FF; HANGUL - 0x1200, // 1200..139F; ETHIOPIC - 0x13A0, // 13A0..13FF; CHEROKEE + 0x1200, // 1200..1248; ETHIOPIC + 0x1249, // 1249 ; UNKNOWN + 0x124A, // 124A..124D; ETHIOPIC + 0x124E, // 124E..124F; UNKNOWN + 0x1250, // 1250..1256; ETHIOPIC + 0x1257, // 1257 ; UNKNOWN + 0x1258, // 1258 ; ETHIOPIC + 0x1259, // 1259 ; UNKNOWN + 0x125A, // 125A..125D; ETHIOPIC + 0x125E, // 125E..125F; UNKNOWN + 0x1260, // 1260..1288; ETHIOPIC + 0x1289, // 1289 ; UNKNOWN + 0x128A, // 128A..128D; ETHIOPIC + 0x128E, // 128E..128F; UNKNOWN + 0x1290, // 1290..12B0; ETHIOPIC + 0x12B1, // 12B1 ; UNKNOWN + 0x12B2, // 12B2..12B5; ETHIOPIC + 0x12B6, // 12B6..12B7; UNKNOWN + 0x12B8, // 12B8..12BE; ETHIOPIC + 0x12BF, // 12BF ; UNKNOWN + 0x12C0, // 12C0 ; ETHIOPIC + 0x12C1, // 12C1 ; UNKNOWN + 0x12C2, // 12C2..12C5; ETHIOPIC + 0x12C6, // 12C6..12C7; UNKNOWN + 0x12C8, // 12C8..12D6; ETHIOPIC + 0x12D7, // 12D7 ; UNKNOWN + 0x12D8, // 12D8..1310; ETHIOPIC + 0x1311, // 1311 ; UNKNOWN + 0x1312, // 1312..1315; ETHIOPIC + 0x1316, // 1316..1317; UNKNOWN + 0x1318, // 1318..135A; ETHIOPIC + 0x135B, // 135B..135C; UNKNOWN + 0x135D, // 135D..137C; ETHIOPIC + 0x137D, // 137D..137F; UNKNOWN + 0x1380, // 1380..1399; ETHIOPIC + 0x139A, // 139A..139F; UNKNOWN + 0x13A0, // 13A0..13F4; CHEROKEE + 0x13F5, // 13F5..13FF; UNKNOWN 0x1400, // 1400..167F; CANADIAN_ABORIGINAL - 0x1680, // 1680..169F; OGHAM + 0x1680, // 1680..169C; OGHAM + 0x169D, // 169D..169F; UNKNOWN 0x16A0, // 16A0..16EA; RUNIC 0x16EB, // 16EB..16ED; COMMON - 0x16EE, // 16EE..16FF; RUNIC - 0x1700, // 1700..171F; TAGALOG + 0x16EE, // 16EE..16F8; RUNIC + 0x16F9, // 16F9..16FF; UNKNOWN + 0x1700, // 1700..170C; TAGALOG + 0x170D, // 170D ; UNKNOWN + 0x170E, // 170E..1714; TAGALOG + 0x1715, // 1715..171F; UNKNOWN 0x1720, // 1720..1734; HANUNOO - 0x1735, // 1735..173F; COMMON - 0x1740, // 1740..175F; BUHID - 0x1760, // 1760..177F; TAGBANWA - 0x1780, // 1780..17FF; KHMER + 0x1735, // 1735..1736; COMMON + 0x1737, // 1737..173F; UNKNOWN + 0x1740, // 1740..1753; BUHID + 0x1754, // 1754..175F; UNKNOWN + 0x1760, // 1760..176C; TAGBANWA + 0x176D, // 176D ; UNKNOWN + 0x176E, // 176E..1770; TAGBANWA + 0x1771, // 1771 ; UNKNOWN + 0x1772, // 1772..1773; TAGBANWA + 0x1774, // 1774..177F; UNKNOWN + 0x1780, // 1780..17DD; KHMER + 0x17DE, // 17DE..17DF; UNKNOWN + 0x17E0, // 17E0..17E9; KHMER + 0x17EA, // 17EA..17EF; UNKNOWN + 0x17F0, // 17F0..17F9; KHMER + 0x17FA, // 17FA..17FF; UNKNOWN 0x1800, // 1800..1801; MONGOLIAN 0x1802, // 1802..1803; COMMON - 0x1804, // 1804..1804; MONGOLIAN - 0x1805, // 1805..1805; COMMON - 0x1806, // 1806..18AF; MONGOLIAN - 0x18B0, // 18B0..18FF; CANADIAN_ABORIGINAL - 0x1900, // 1900..194F; LIMBU - 0x1950, // 1950..197F; TAI_LE - 0x1980, // 1980..19DF; NEW_TAI_LUE + 0x1804, // 1804 ; MONGOLIAN + 0x1805, // 1805 ; COMMON + 0x1806, // 1806..180E; MONGOLIAN + 0x180F, // 180F ; UNKNOWN + 0x1810, // 1810..1819; MONGOLIAN + 0x181A, // 181A..181F; UNKNOWN + 0x1820, // 1820..1877; MONGOLIAN + 0x1878, // 1878..187F; UNKNOWN + 0x1880, // 1880..18AA; MONGOLIAN + 0x18AB, // 18AB..18AF; UNKNOWN + 0x18B0, // 18B0..18F5; CANADIAN_ABORIGINAL + 0x18F6, // 18F6..18FF; UNKNOWN + 0x1900, // 1900..191E; LIMBU + 0x191F, // 191F ; UNKNOWN + 0x1920, // 1920..192B; LIMBU + 0x192C, // 192C..192F; UNKNOWN + 0x1930, // 1930..193B; LIMBU + 0x193C, // 193C..193F; UNKNOWN + 0x1940, // 1940 ; LIMBU + 0x1941, // 1941..1943; UNKNOWN + 0x1944, // 1944..194F; LIMBU + 0x1950, // 1950..196D; TAI_LE + 0x196E, // 196E..196F; UNKNOWN + 0x1970, // 1970..1974; TAI_LE + 0x1975, // 1975..197F; UNKNOWN + 0x1980, // 1980..19AB; NEW_TAI_LUE + 0x19AC, // 19AC..19AF; UNKNOWN + 0x19B0, // 19B0..19C9; NEW_TAI_LUE + 0x19CA, // 19CA..19CF; UNKNOWN + 0x19D0, // 19D0..19DA; NEW_TAI_LUE + 0x19DB, // 19DB..19DD; UNKNOWN + 0x19DE, // 19DE..19DF; NEW_TAI_LUE 0x19E0, // 19E0..19FF; KHMER - 0x1A00, // 1A00..1A1F; BUGINESE - 0x1A20, // 1A20..1AFF; TAI_THAM - 0x1B00, // 1B00..1B7F; BALINESE + 0x1A00, // 1A00..1A1B; BUGINESE + 0x1A1C, // 1A1C..1A1D; UNKNOWN + 0x1A1E, // 1A1E..1A1F; BUGINESE + 0x1A20, // 1A20..1A5E; TAI_THAM + 0x1A5F, // 1A5F ; UNKNOWN + 0x1A60, // 1A60..1A7C; TAI_THAM + 0x1A7D, // 1A7D..1A7E; UNKNOWN + 0x1A7F, // 1A7F..1A89; TAI_THAM + 0x1A8A, // 1A8A..1A8F; UNKNOWN + 0x1A90, // 1A90..1A99; TAI_THAM + 0x1A9A, // 1A9A..1A9F; UNKNOWN + 0x1AA0, // 1AA0..1AAD; TAI_THAM + 0x1AAE, // 1AAE..1AAF; UNKNOWN + 0x1AB0, // 1AB0..1ABE; INHERITED + 0x1ABF, // 1ABF..1AFF; UNKNOWN + 0x1B00, // 1B00..1B4B; BALINESE + 0x1B4C, // 1B4C..1B4F; UNKNOWN + 0x1B50, // 1B50..1B7C; BALINESE + 0x1B7D, // 1B7D..1B7F; UNKNOWN 0x1B80, // 1B80..1BBF; SUNDANESE - 0x1BC0, // 1BC0..1BFF; BATAK - 0x1C00, // 1C00..1C4F; LEPCHA - 0x1C50, // 1C50..1CBF; OL_CHIKI - 0x1CC0, // 1CC0..1CCF; SUNDANESE + 0x1BC0, // 1BC0..1BF3; BATAK + 0x1BF4, // 1BF4..1BFB; UNKNOWN + 0x1BFC, // 1BFC..1BFF; BATAK + 0x1C00, // 1C00..1C37; LEPCHA + 0x1C38, // 1C38..1C3A; UNKNOWN + 0x1C3B, // 1C3B..1C49; LEPCHA + 0x1C4A, // 1C4A..1C4C; UNKNOWN + 0x1C4D, // 1C4D..1C4F; LEPCHA + 0x1C50, // 1C50..1C7F; OL_CHIKI + 0x1C80, // 1C80..1CBF; UNKNOWN + 0x1CC0, // 1CC0..1CC7; SUNDANESE + 0x1CC8, // 1CC8..1CCF; UNKNOWN 0x1CD0, // 1CD0..1CD2; INHERITED - 0x1CD3, // 1CD3..1CD3; COMMON + 0x1CD3, // 1CD3 ; COMMON 0x1CD4, // 1CD4..1CE0; INHERITED - 0x1CE1, // 1CE1..1CE1; COMMON + 0x1CE1, // 1CE1 ; COMMON 0x1CE2, // 1CE2..1CE8; INHERITED 0x1CE9, // 1CE9..1CEC; COMMON - 0x1CED, // 1CED..1CED; INHERITED + 0x1CED, // 1CED ; INHERITED 0x1CEE, // 1CEE..1CF3; COMMON - 0x1CF4, // 1CF4..1CF4; INHERITED - 0x1CF5, // 1CF5..1CFF; COMMON + 0x1CF4, // 1CF4 ; INHERITED + 0x1CF5, // 1CF5..1CF6; COMMON + 0x1CF7, // 1CF7 ; UNKNOWN + 0x1CF8, // 1CF8..1CF9; INHERITED + 0x1CFA, // 1CFA..1CFF; UNKNOWN 0x1D00, // 1D00..1D25; LATIN 0x1D26, // 1D26..1D2A; GREEK - 0x1D2B, // 1D2B..1D2B; CYRILLIC + 0x1D2B, // 1D2B ; CYRILLIC 0x1D2C, // 1D2C..1D5C; LATIN 0x1D5D, // 1D5D..1D61; GREEK 0x1D62, // 1D62..1D65; LATIN 0x1D66, // 1D66..1D6A; GREEK 0x1D6B, // 1D6B..1D77; LATIN - 0x1D78, // 1D78..1D78; CYRILLIC + 0x1D78, // 1D78 ; CYRILLIC 0x1D79, // 1D79..1DBE; LATIN - 0x1DBF, // 1DBF..1DBF; GREEK - 0x1DC0, // 1DC0..1DFF; INHERITED + 0x1DBF, // 1DBF ; GREEK + 0x1DC0, // 1DC0..1DF5; INHERITED + 0x1DF6, // 1DF6..1DFB; UNKNOWN + 0x1DFC, // 1DFC..1DFF; INHERITED 0x1E00, // 1E00..1EFF; LATIN - 0x1F00, // 1F00..1FFF; GREEK + 0x1F00, // 1F00..1F15; GREEK + 0x1F16, // 1F16..1F17; UNKNOWN + 0x1F18, // 1F18..1F1D; GREEK + 0x1F1E, // 1F1E..1F1F; UNKNOWN + 0x1F20, // 1F20..1F45; GREEK + 0x1F46, // 1F46..1F47; UNKNOWN + 0x1F48, // 1F48..1F4D; GREEK + 0x1F4E, // 1F4E..1F4F; UNKNOWN + 0x1F50, // 1F50..1F57; GREEK + 0x1F58, // 1F58 ; UNKNOWN + 0x1F59, // 1F59 ; GREEK + 0x1F5A, // 1F5A ; UNKNOWN + 0x1F5B, // 1F5B ; GREEK + 0x1F5C, // 1F5C ; UNKNOWN + 0x1F5D, // 1F5D ; GREEK + 0x1F5E, // 1F5E ; UNKNOWN + 0x1F5F, // 1F5F..1F7D; GREEK + 0x1F7E, // 1F7E..1F7F; UNKNOWN + 0x1F80, // 1F80..1FB4; GREEK + 0x1FB5, // 1FB5 ; UNKNOWN + 0x1FB6, // 1FB6..1FC4; GREEK + 0x1FC5, // 1FC5 ; UNKNOWN + 0x1FC6, // 1FC6..1FD3; GREEK + 0x1FD4, // 1FD4..1FD5; UNKNOWN + 0x1FD6, // 1FD6..1FDB; GREEK + 0x1FDC, // 1FDC ; UNKNOWN + 0x1FDD, // 1FDD..1FEF; GREEK + 0x1FF0, // 1FF0..1FF1; UNKNOWN + 0x1FF2, // 1FF2..1FF4; GREEK + 0x1FF5, // 1FF5 ; UNKNOWN + 0x1FF6, // 1FF6..1FFE; GREEK + 0x1FFF, // 1FFF ; UNKNOWN 0x2000, // 2000..200B; COMMON 0x200C, // 200C..200D; INHERITED - 0x200E, // 200E..2070; COMMON - 0x2071, // 2071..2073; LATIN + 0x200E, // 200E..2064; COMMON + 0x2065, // 2065 ; UNKNOWN + 0x2066, // 2066..2070; COMMON + 0x2071, // 2071 ; LATIN + 0x2072, // 2072..2073; UNKNOWN 0x2074, // 2074..207E; COMMON - 0x207F, // 207F..207F; LATIN - 0x2080, // 2080..208F; COMMON - 0x2090, // 2090..209F; LATIN - 0x20A0, // 20A0..20CF; COMMON - 0x20D0, // 20D0..20FF; INHERITED + 0x207F, // 207F ; LATIN + 0x2080, // 2080..208E; COMMON + 0x208F, // 208F ; UNKNOWN + 0x2090, // 2090..209C; LATIN + 0x209D, // 209D..209F; UNKNOWN + 0x20A0, // 20A0..20BD; COMMON + 0x20BE, // 20BE..20CF; UNKNOWN + 0x20D0, // 20D0..20F0; INHERITED + 0x20F1, // 20F1..20FF; UNKNOWN 0x2100, // 2100..2125; COMMON - 0x2126, // 2126..2126; GREEK + 0x2126, // 2126 ; GREEK 0x2127, // 2127..2129; COMMON 0x212A, // 212A..212B; LATIN 0x212C, // 212C..2131; COMMON - 0x2132, // 2132..2132; LATIN + 0x2132, // 2132 ; LATIN 0x2133, // 2133..214D; COMMON - 0x214E, // 214E..214E; LATIN + 0x214E, // 214E ; LATIN 0x214F, // 214F..215F; COMMON 0x2160, // 2160..2188; LATIN - 0x2189, // 2189..27FF; COMMON + 0x2189, // 2189 ; COMMON + 0x218A, // 218A..218F; UNKNOWN + 0x2190, // 2190..23FA; COMMON + 0x23FB, // 23FB..23FF; UNKNOWN + 0x2400, // 2400..2426; COMMON + 0x2427, // 2427..243F; UNKNOWN + 0x2440, // 2440..244A; COMMON + 0x244B, // 244B..245F; UNKNOWN + 0x2460, // 2460..27FF; COMMON 0x2800, // 2800..28FF; BRAILLE - 0x2900, // 2900..2BFF; COMMON - 0x2C00, // 2C00..2C5F; GLAGOLITIC + 0x2900, // 2900..2B73; COMMON + 0x2B74, // 2B74..2B75; UNKNOWN + 0x2B76, // 2B76..2B95; COMMON + 0x2B96, // 2B96..2B97; UNKNOWN + 0x2B98, // 2B98..2BB9; COMMON + 0x2BBA, // 2BBA..2BBC; UNKNOWN + 0x2BBD, // 2BBD..2BC8; COMMON + 0x2BC9, // 2BC9 ; UNKNOWN + 0x2BCA, // 2BCA..2BD1; COMMON + 0x2BD2, // 2BD2..2BFF; UNKNOWN + 0x2C00, // 2C00..2C2E; GLAGOLITIC + 0x2C2F, // 2C2F ; UNKNOWN + 0x2C30, // 2C30..2C5E; GLAGOLITIC + 0x2C5F, // 2C5F ; UNKNOWN 0x2C60, // 2C60..2C7F; LATIN - 0x2C80, // 2C80..2CFF; COPTIC - 0x2D00, // 2D00..2D2F; GEORGIAN - 0x2D30, // 2D30..2D7F; TIFINAGH - 0x2D80, // 2D80..2DDF; ETHIOPIC + 0x2C80, // 2C80..2CF3; COPTIC + 0x2CF4, // 2CF4..2CF8; UNKNOWN + 0x2CF9, // 2CF9..2CFF; COPTIC + 0x2D00, // 2D00..2D25; GEORGIAN + 0x2D26, // 2D26 ; UNKNOWN + 0x2D27, // 2D27 ; GEORGIAN + 0x2D28, // 2D28..2D2C; UNKNOWN + 0x2D2D, // 2D2D ; GEORGIAN + 0x2D2E, // 2D2E..2D2F; UNKNOWN + 0x2D30, // 2D30..2D67; TIFINAGH + 0x2D68, // 2D68..2D6E; UNKNOWN + 0x2D6F, // 2D6F..2D70; TIFINAGH + 0x2D71, // 2D71..2D7E; UNKNOWN + 0x2D7F, // 2D7F ; TIFINAGH + 0x2D80, // 2D80..2D96; ETHIOPIC + 0x2D97, // 2D97..2D9F; UNKNOWN + 0x2DA0, // 2DA0..2DA6; ETHIOPIC + 0x2DA7, // 2DA7 ; UNKNOWN + 0x2DA8, // 2DA8..2DAE; ETHIOPIC + 0x2DAF, // 2DAF ; UNKNOWN + 0x2DB0, // 2DB0..2DB6; ETHIOPIC + 0x2DB7, // 2DB7 ; UNKNOWN + 0x2DB8, // 2DB8..2DBE; ETHIOPIC + 0x2DBF, // 2DBF ; UNKNOWN + 0x2DC0, // 2DC0..2DC6; ETHIOPIC + 0x2DC7, // 2DC7 ; UNKNOWN + 0x2DC8, // 2DC8..2DCE; ETHIOPIC + 0x2DCF, // 2DCF ; UNKNOWN + 0x2DD0, // 2DD0..2DD6; ETHIOPIC + 0x2DD7, // 2DD7 ; UNKNOWN + 0x2DD8, // 2DD8..2DDE; ETHIOPIC + 0x2DDF, // 2DDF ; UNKNOWN 0x2DE0, // 2DE0..2DFF; CYRILLIC - 0x2E00, // 2E00..2E7F; COMMON - 0x2E80, // 2E80..2FEF; HAN - 0x2FF0, // 2FF0..3004; COMMON - 0x3005, // 3005..3005; HAN - 0x3006, // 3006..3006; COMMON - 0x3007, // 3007..3007; HAN + 0x2E00, // 2E00..2E42; COMMON + 0x2E43, // 2E43..2E7F; UNKNOWN + 0x2E80, // 2E80..2E99; HAN + 0x2E9A, // 2E9A ; UNKNOWN + 0x2E9B, // 2E9B..2EF3; HAN + 0x2EF4, // 2EF4..2EFF; UNKNOWN + 0x2F00, // 2F00..2FD5; HAN + 0x2FD6, // 2FD6..2FEF; UNKNOWN + 0x2FF0, // 2FF0..2FFB; COMMON + 0x2FFC, // 2FFC..2FFF; UNKNOWN + 0x3000, // 3000..3004; COMMON + 0x3005, // 3005 ; HAN + 0x3006, // 3006 ; COMMON + 0x3007, // 3007 ; HAN 0x3008, // 3008..3020; COMMON 0x3021, // 3021..3029; HAN 0x302A, // 302A..302D; INHERITED 0x302E, // 302E..302F; HANGUL 0x3030, // 3030..3037; COMMON 0x3038, // 3038..303B; HAN - 0x303C, // 303C..3040; COMMON - 0x3041, // 3041..3098; HIRAGANA + 0x303C, // 303C..303F; COMMON + 0x3040, // 3040 ; UNKNOWN + 0x3041, // 3041..3096; HIRAGANA + 0x3097, // 3097..3098; UNKNOWN 0x3099, // 3099..309A; INHERITED 0x309B, // 309B..309C; COMMON 0x309D, // 309D..309F; HIRAGANA - 0x30A0, // 30A0..30A0; COMMON + 0x30A0, // 30A0 ; COMMON 0x30A1, // 30A1..30FA; KATAKANA 0x30FB, // 30FB..30FC; COMMON - 0x30FD, // 30FD..3104; KATAKANA - 0x3105, // 3105..3130; BOPOMOFO - 0x3131, // 3131..318F; HANGUL + 0x30FD, // 30FD..30FF; KATAKANA + 0x3100, // 3100..3104; UNKNOWN + 0x3105, // 3105..312D; BOPOMOFO + 0x312E, // 312E..3130; UNKNOWN + 0x3131, // 3131..318E; HANGUL + 0x318F, // 318F ; UNKNOWN 0x3190, // 3190..319F; COMMON - 0x31A0, // 31A0..31BF; BOPOMOFO - 0x31C0, // 31C0..31EF; COMMON + 0x31A0, // 31A0..31BA; BOPOMOFO + 0x31BB, // 31BB..31BF; UNKNOWN + 0x31C0, // 31C0..31E3; COMMON + 0x31E4, // 31E4..31EF; UNKNOWN 0x31F0, // 31F0..31FF; KATAKANA - 0x3200, // 3200..321F; HANGUL + 0x3200, // 3200..321E; HANGUL + 0x321F, // 321F ; UNKNOWN 0x3220, // 3220..325F; COMMON 0x3260, // 3260..327E; HANGUL 0x327F, // 327F..32CF; COMMON - 0x32D0, // 32D0..3357; KATAKANA + 0x32D0, // 32D0..32FE; KATAKANA + 0x32FF, // 32FF ; UNKNOWN + 0x3300, // 3300..3357; KATAKANA 0x3358, // 3358..33FF; COMMON - 0x3400, // 3400..4DBF; HAN + 0x3400, // 3400..4DB5; HAN + 0x4DB6, // 4DB6..4DBF; UNKNOWN 0x4DC0, // 4DC0..4DFF; COMMON - 0x4E00, // 4E00..9FFF; HAN - 0xA000, // A000..A4CF; YI + 0x4E00, // 4E00..9FCC; HAN + 0x9FCD, // 9FCD..9FFF; UNKNOWN + 0xA000, // A000..A48C; YI + 0xA48D, // A48D..A48F; UNKNOWN + 0xA490, // A490..A4C6; YI + 0xA4C7, // A4C7..A4CF; UNKNOWN 0xA4D0, // A4D0..A4FF; LISU - 0xA500, // A500..A63F; VAI - 0xA640, // A640..A69F; CYRILLIC - 0xA6A0, // A6A0..A6FF; BAMUM + 0xA500, // A500..A62B; VAI + 0xA62C, // A62C..A63F; UNKNOWN + 0xA640, // A640..A69D; CYRILLIC + 0xA69E, // A69E ; UNKNOWN + 0xA69F, // A69F ; CYRILLIC + 0xA6A0, // A6A0..A6F7; BAMUM + 0xA6F8, // A6F8..A6FF; UNKNOWN 0xA700, // A700..A721; COMMON 0xA722, // A722..A787; LATIN 0xA788, // A788..A78A; COMMON - 0xA78B, // A78B..A7FF; LATIN - 0xA800, // A800..A82F; SYLOTI_NAGRI - 0xA830, // A830..A83F; COMMON - 0xA840, // A840..A87F; PHAGS_PA - 0xA880, // A880..A8DF; SAURASHTRA - 0xA8E0, // A8E0..A8FF; DEVANAGARI - 0xA900, // A900..A92F; KAYAH_LI - 0xA930, // A930..A95F; REJANG - 0xA960, // A960..A97F; HANGUL - 0xA980, // A980..A9FF; JAVANESE - 0xAA00, // AA00..AA5F; CHAM + 0xA78B, // A78B..A78E; LATIN + 0xA78F, // A78F ; UNKNOWN + 0xA790, // A790..A7AD; LATIN + 0xA7AE, // A7AE..A7AF; UNKNOWN + 0xA7B0, // A7B0..A7B1; LATIN + 0xA7B2, // A7B2..A7F6; UNKNOWN + 0xA7F7, // A7F7..A7FF; LATIN + 0xA800, // A800..A82B; SYLOTI_NAGRI + 0xA82C, // A82C..A82F; UNKNOWN + 0xA830, // A830..A839; COMMON + 0xA83A, // A83A..A83F; UNKNOWN + 0xA840, // A840..A877; PHAGS_PA + 0xA878, // A878..A87F; UNKNOWN + 0xA880, // A880..A8C4; SAURASHTRA + 0xA8C5, // A8C5..A8CD; UNKNOWN + 0xA8CE, // A8CE..A8D9; SAURASHTRA + 0xA8DA, // A8DA..A8DF; UNKNOWN + 0xA8E0, // A8E0..A8FB; DEVANAGARI + 0xA8FC, // A8FC..A8FF; UNKNOWN + 0xA900, // A900..A92D; KAYAH_LI + 0xA92E, // A92E ; COMMON + 0xA92F, // A92F ; KAYAH_LI + 0xA930, // A930..A953; REJANG + 0xA954, // A954..A95E; UNKNOWN + 0xA95F, // A95F ; REJANG + 0xA960, // A960..A97C; HANGUL + 0xA97D, // A97D..A97F; UNKNOWN + 0xA980, // A980..A9CD; JAVANESE + 0xA9CE, // A9CE ; UNKNOWN + 0xA9CF, // A9CF ; COMMON + 0xA9D0, // A9D0..A9D9; JAVANESE + 0xA9DA, // A9DA..A9DD; UNKNOWN + 0xA9DE, // A9DE..A9DF; JAVANESE + 0xA9E0, // A9E0..A9FE; MYANMAR + 0xA9FF, // A9FF ; UNKNOWN + 0xAA00, // AA00..AA36; CHAM + 0xAA37, // AA37..AA3F; UNKNOWN + 0xAA40, // AA40..AA4D; CHAM + 0xAA4E, // AA4E..AA4F; UNKNOWN + 0xAA50, // AA50..AA59; CHAM + 0xAA5A, // AA5A..AA5B; UNKNOWN + 0xAA5C, // AA5C..AA5F; CHAM 0xAA60, // AA60..AA7F; MYANMAR - 0xAA80, // AA80..AADF; TAI_VIET - 0xAAE0, // AAE0..AB00; MEETEI_MAYEK - 0xAB01, // AB01..ABBF; ETHIOPIC - 0xABC0, // ABC0..ABFF; MEETEI_MAYEK - 0xAC00, // AC00..D7FB; HANGUL + 0xAA80, // AA80..AAC2; TAI_VIET + 0xAAC3, // AAC3..AADA; UNKNOWN + 0xAADB, // AADB..AADF; TAI_VIET + 0xAAE0, // AAE0..AAF6; MEETEI_MAYEK + 0xAAF7, // AAF7..AB00; UNKNOWN + 0xAB01, // AB01..AB06; ETHIOPIC + 0xAB07, // AB07..AB08; UNKNOWN + 0xAB09, // AB09..AB0E; ETHIOPIC + 0xAB0F, // AB0F..AB10; UNKNOWN + 0xAB11, // AB11..AB16; ETHIOPIC + 0xAB17, // AB17..AB1F; UNKNOWN + 0xAB20, // AB20..AB26; ETHIOPIC + 0xAB27, // AB27 ; UNKNOWN + 0xAB28, // AB28..AB2E; ETHIOPIC + 0xAB2F, // AB2F ; UNKNOWN + 0xAB30, // AB30..AB5A; LATIN + 0xAB5B, // AB5B ; COMMON + 0xAB5C, // AB5C..AB5F; LATIN + 0xAB60, // AB60..AB63; UNKNOWN + 0xAB64, // AB64 ; LATIN + 0xAB65, // AB65 ; GREEK + 0xAB66, // AB66..ABBF; UNKNOWN + 0xABC0, // ABC0..ABED; MEETEI_MAYEK + 0xABEE, // ABEE..ABEF; UNKNOWN + 0xABF0, // ABF0..ABF9; MEETEI_MAYEK + 0xABFA, // ABFA..ABFF; UNKNOWN + 0xAC00, // AC00..D7A3; HANGUL + 0xD7A4, // D7A4..D7AF; UNKNOWN + 0xD7B0, // D7B0..D7C6; HANGUL + 0xD7C7, // D7C7..D7CA; UNKNOWN + 0xD7CB, // D7CB..D7FB; HANGUL 0xD7FC, // D7FC..F8FF; UNKNOWN - 0xF900, // F900..FAFF; HAN - 0xFB00, // FB00..FB12; LATIN - 0xFB13, // FB13..FB1C; ARMENIAN - 0xFB1D, // FB1D..FB4F; HEBREW - 0xFB50, // FB50..FD3D; ARABIC - 0xFD3E, // FD3E..FD4F; COMMON - 0xFD50, // FD50..FDFC; ARABIC - 0xFDFD, // FDFD..FDFF; COMMON + 0xF900, // F900..FA6D; HAN + 0xFA6E, // FA6E..FA6F; UNKNOWN + 0xFA70, // FA70..FAD9; HAN + 0xFADA, // FADA..FAFF; UNKNOWN + 0xFB00, // FB00..FB06; LATIN + 0xFB07, // FB07..FB12; UNKNOWN + 0xFB13, // FB13..FB17; ARMENIAN + 0xFB18, // FB18..FB1C; UNKNOWN + 0xFB1D, // FB1D..FB36; HEBREW + 0xFB37, // FB37 ; UNKNOWN + 0xFB38, // FB38..FB3C; HEBREW + 0xFB3D, // FB3D ; UNKNOWN + 0xFB3E, // FB3E ; HEBREW + 0xFB3F, // FB3F ; UNKNOWN + 0xFB40, // FB40..FB41; HEBREW + 0xFB42, // FB42 ; UNKNOWN + 0xFB43, // FB43..FB44; HEBREW + 0xFB45, // FB45 ; UNKNOWN + 0xFB46, // FB46..FB4F; HEBREW + 0xFB50, // FB50..FBC1; ARABIC + 0xFBC2, // FBC2..FBD2; UNKNOWN + 0xFBD3, // FBD3..FD3D; ARABIC + 0xFD3E, // FD3E..FD3F; COMMON + 0xFD40, // FD40..FD4F; UNKNOWN + 0xFD50, // FD50..FD8F; ARABIC + 0xFD90, // FD90..FD91; UNKNOWN + 0xFD92, // FD92..FDC7; ARABIC + 0xFDC8, // FDC8..FDEF; UNKNOWN + 0xFDF0, // FDF0..FDFD; ARABIC + 0xFDFE, // FDFE..FDFF; UNKNOWN 0xFE00, // FE00..FE0F; INHERITED - 0xFE10, // FE10..FE1F; COMMON - 0xFE20, // FE20..FE2F; INHERITED - 0xFE30, // FE30..FE6F; COMMON - 0xFE70, // FE70..FEFE; ARABIC - 0xFEFF, // FEFF..FF20; COMMON + 0xFE10, // FE10..FE19; COMMON + 0xFE1A, // FE1A..FE1F; UNKNOWN + 0xFE20, // FE20..FE2D; INHERITED + 0xFE2E, // FE2E..FE2F; UNKNOWN + 0xFE30, // FE30..FE52; COMMON + 0xFE53, // FE53 ; UNKNOWN + 0xFE54, // FE54..FE66; COMMON + 0xFE67, // FE67 ; UNKNOWN + 0xFE68, // FE68..FE6B; COMMON + 0xFE6C, // FE6C..FE6F; UNKNOWN + 0xFE70, // FE70..FE74; ARABIC + 0xFE75, // FE75 ; UNKNOWN + 0xFE76, // FE76..FEFC; ARABIC + 0xFEFD, // FEFD..FEFE; UNKNOWN + 0xFEFF, // FEFF ; COMMON + 0xFF00, // FF00 ; UNKNOWN + 0xFF01, // FF01..FF20; COMMON 0xFF21, // FF21..FF3A; LATIN 0xFF3B, // FF3B..FF40; COMMON 0xFF41, // FF41..FF5A; LATIN 0xFF5B, // FF5B..FF65; COMMON 0xFF66, // FF66..FF6F; KATAKANA - 0xFF70, // FF70..FF70; COMMON + 0xFF70, // FF70 ; COMMON 0xFF71, // FF71..FF9D; KATAKANA 0xFF9E, // FF9E..FF9F; COMMON - 0xFFA0, // FFA0..FFDF; HANGUL - 0xFFE0, // FFE0..FFFF; COMMON - 0x10000, // 10000..100FF; LINEAR_B - 0x10100, // 10100..1013F; COMMON - 0x10140, // 10140..1018F; GREEK - 0x10190, // 10190..101FC; COMMON - 0x101FD, // 101FD..1027F; INHERITED - 0x10280, // 10280..1029F; LYCIAN - 0x102A0, // 102A0..102FF; CARIAN - 0x10300, // 10300..1032F; OLD_ITALIC - 0x10330, // 10330..1037F; GOTHIC - 0x10380, // 10380..1039F; UGARITIC - 0x103A0, // 103A0..103FF; OLD_PERSIAN + 0xFFA0, // FFA0..FFBE; HANGUL + 0xFFBF, // FFBF..FFC1; UNKNOWN + 0xFFC2, // FFC2..FFC7; HANGUL + 0xFFC8, // FFC8..FFC9; UNKNOWN + 0xFFCA, // FFCA..FFCF; HANGUL + 0xFFD0, // FFD0..FFD1; UNKNOWN + 0xFFD2, // FFD2..FFD7; HANGUL + 0xFFD8, // FFD8..FFD9; UNKNOWN + 0xFFDA, // FFDA..FFDC; HANGUL + 0xFFDD, // FFDD..FFDF; UNKNOWN + 0xFFE0, // FFE0..FFE6; COMMON + 0xFFE7, // FFE7 ; UNKNOWN + 0xFFE8, // FFE8..FFEE; COMMON + 0xFFEF, // FFEF..FFF8; UNKNOWN + 0xFFF9, // FFF9..FFFD; COMMON + 0xFFFE, // FFFE..FFFF; UNKNOWN + 0x10000, // 10000..1000B; LINEAR_B + 0x1000C, // 1000C ; UNKNOWN + 0x1000D, // 1000D..10026; LINEAR_B + 0x10027, // 10027 ; UNKNOWN + 0x10028, // 10028..1003A; LINEAR_B + 0x1003B, // 1003B ; UNKNOWN + 0x1003C, // 1003C..1003D; LINEAR_B + 0x1003E, // 1003E ; UNKNOWN + 0x1003F, // 1003F..1004D; LINEAR_B + 0x1004E, // 1004E..1004F; UNKNOWN + 0x10050, // 10050..1005D; LINEAR_B + 0x1005E, // 1005E..1007F; UNKNOWN + 0x10080, // 10080..100FA; LINEAR_B + 0x100FB, // 100FB..100FF; UNKNOWN + 0x10100, // 10100..10102; COMMON + 0x10103, // 10103..10106; UNKNOWN + 0x10107, // 10107..10133; COMMON + 0x10134, // 10134..10136; UNKNOWN + 0x10137, // 10137..1013F; COMMON + 0x10140, // 10140..1018C; GREEK + 0x1018D, // 1018D..1018F; UNKNOWN + 0x10190, // 10190..1019B; COMMON + 0x1019C, // 1019C..1019F; UNKNOWN + 0x101A0, // 101A0 ; GREEK + 0x101A1, // 101A1..101CF; UNKNOWN + 0x101D0, // 101D0..101FC; COMMON + 0x101FD, // 101FD ; INHERITED + 0x101FE, // 101FE..1027F; UNKNOWN + 0x10280, // 10280..1029C; LYCIAN + 0x1029D, // 1029D..1029F; UNKNOWN + 0x102A0, // 102A0..102D0; CARIAN + 0x102D1, // 102D1..102DF; UNKNOWN + 0x102E0, // 102E0 ; INHERITED + 0x102E1, // 102E1..102FB; COMMON + 0x102FC, // 102FC..102FF; UNKNOWN + 0x10300, // 10300..10323; OLD_ITALIC + 0x10324, // 10324..1032F; UNKNOWN + 0x10330, // 10330..1034A; GOTHIC + 0x1034B, // 1034B..1034F; UNKNOWN + 0x10350, // 10350..1037A; OLD_PERMIC + 0x1037B, // 1037B..1037F; UNKNOWN + 0x10380, // 10380..1039D; UGARITIC + 0x1039E, // 1039E ; UNKNOWN + 0x1039F, // 1039F ; UGARITIC + 0x103A0, // 103A0..103C3; OLD_PERSIAN + 0x103C4, // 103C4..103C7; UNKNOWN + 0x103C8, // 103C8..103D5; OLD_PERSIAN + 0x103D6, // 103D6..103FF; UNKNOWN 0x10400, // 10400..1044F; DESERET 0x10450, // 10450..1047F; SHAVIAN - 0x10480, // 10480..107FF; OSMANYA - 0x10800, // 10800..1083F; CYPRIOT - 0x10840, // 10840..108FF; IMPERIAL_ARAMAIC - 0x10900, // 10900..1091F; PHOENICIAN - 0x10920, // 10920..1097F; LYDIAN + 0x10480, // 10480..1049D; OSMANYA + 0x1049E, // 1049E..1049F; UNKNOWN + 0x104A0, // 104A0..104A9; OSMANYA + 0x104AA, // 104AA..104FF; UNKNOWN + 0x10500, // 10500..10527; ELBASAN + 0x10528, // 10528..1052F; UNKNOWN + 0x10530, // 10530..10563; CAUCASIAN_ALBANIAN + 0x10564, // 10564..1056E; UNKNOWN + 0x1056F, // 1056F ; CAUCASIAN_ALBANIAN + 0x10570, // 10570..105FF; UNKNOWN + 0x10600, // 10600..10736; LINEAR_A + 0x10737, // 10737..1073F; UNKNOWN + 0x10740, // 10740..10755; LINEAR_A + 0x10756, // 10756..1075F; UNKNOWN + 0x10760, // 10760..10767; LINEAR_A + 0x10768, // 10768..107FF; UNKNOWN + 0x10800, // 10800..10805; CYPRIOT + 0x10806, // 10806..10807; UNKNOWN + 0x10808, // 10808 ; CYPRIOT + 0x10809, // 10809 ; UNKNOWN + 0x1080A, // 1080A..10835; CYPRIOT + 0x10836, // 10836 ; UNKNOWN + 0x10837, // 10837..10838; CYPRIOT + 0x10839, // 10839..1083B; UNKNOWN + 0x1083C, // 1083C ; CYPRIOT + 0x1083D, // 1083D..1083E; UNKNOWN + 0x1083F, // 1083F ; CYPRIOT + 0x10840, // 10840..10855; IMPERIAL_ARAMAIC + 0x10856, // 10856 ; UNKNOWN + 0x10857, // 10857..1085F; IMPERIAL_ARAMAIC + 0x10860, // 10860..1087F; PALMYRENE + 0x10880, // 10880..1089E; NABATAEAN + 0x1089F, // 1089F..108A6; UNKNOWN + 0x108A7, // 108A7..108AF; NABATAEAN + 0x108B0, // 108B0..108FF; UNKNOWN + 0x10900, // 10900..1091B; PHOENICIAN + 0x1091C, // 1091C..1091E; UNKNOWN + 0x1091F, // 1091F ; PHOENICIAN + 0x10920, // 10920..10939; LYDIAN + 0x1093A, // 1093A..1093E; UNKNOWN + 0x1093F, // 1093F ; LYDIAN + 0x10940, // 10940..1097F; UNKNOWN 0x10980, // 10980..1099F; MEROITIC_HIEROGLYPHS - 0x109A0, // 109A0..109FF; MEROITIC_CURSIVE - 0x10A00, // 10A00..10A5F; KHAROSHTHI - 0x10A60, // 10A60..10AFF; OLD_SOUTH_ARABIAN - 0x10B00, // 10B00..10B3F; AVESTAN - 0x10B40, // 10B40..10B5F; INSCRIPTIONAL_PARTHIAN - 0x10B60, // 10B60..10BFF; INSCRIPTIONAL_PAHLAVI - 0x10C00, // 10C00..10E5F; OLD_TURKIC - 0x10E60, // 10E60..10FFF; ARABIC - 0x11000, // 11000..1107F; BRAHMI - 0x11080, // 11080..110CF; KAITHI - 0x110D0, // 110D0..110FF; SORA_SOMPENG - 0x11100, // 11100..1117F; CHAKMA - 0x11180, // 11180..1167F; SHARADA - 0x11680, // 11680..116CF; TAKRI - 0x12000, // 12000..12FFF; CUNEIFORM - 0x13000, // 13000..167FF; EGYPTIAN_HIEROGLYPHS + 0x109A0, // 109A0..109B7; MEROITIC_CURSIVE + 0x109B8, // 109B8..109BD; UNKNOWN + 0x109BE, // 109BE..109BF; MEROITIC_CURSIVE + 0x109C0, // 109C0..109FF; UNKNOWN + 0x10A00, // 10A00..10A03; KHAROSHTHI + 0x10A04, // 10A04 ; UNKNOWN + 0x10A05, // 10A05..10A06; KHAROSHTHI + 0x10A07, // 10A07..10A0B; UNKNOWN + 0x10A0C, // 10A0C..10A13; KHAROSHTHI + 0x10A14, // 10A14 ; UNKNOWN + 0x10A15, // 10A15..10A17; KHAROSHTHI + 0x10A18, // 10A18 ; UNKNOWN + 0x10A19, // 10A19..10A33; KHAROSHTHI + 0x10A34, // 10A34..10A37; UNKNOWN + 0x10A38, // 10A38..10A3A; KHAROSHTHI + 0x10A3B, // 10A3B..10A3E; UNKNOWN + 0x10A3F, // 10A3F..10A47; KHAROSHTHI + 0x10A48, // 10A48..10A4F; UNKNOWN + 0x10A50, // 10A50..10A58; KHAROSHTHI + 0x10A59, // 10A59..10A5F; UNKNOWN + 0x10A60, // 10A60..10A7F; OLD_SOUTH_ARABIAN + 0x10A80, // 10A80..10A9F; OLD_NORTH_ARABIAN + 0x10AA0, // 10AA0..10ABF; UNKNOWN + 0x10AC0, // 10AC0..10AE6; MANICHAEAN + 0x10AE7, // 10AE7..10AEA; UNKNOWN + 0x10AEB, // 10AEB..10AF6; MANICHAEAN + 0x10AF7, // 10AF7..10AFF; UNKNOWN + 0x10B00, // 10B00..10B35; AVESTAN + 0x10B36, // 10B36..10B38; UNKNOWN + 0x10B39, // 10B39..10B3F; AVESTAN + 0x10B40, // 10B40..10B55; INSCRIPTIONAL_PARTHIAN + 0x10B56, // 10B56..10B57; UNKNOWN + 0x10B58, // 10B58..10B5F; INSCRIPTIONAL_PARTHIAN + 0x10B60, // 10B60..10B72; INSCRIPTIONAL_PAHLAVI + 0x10B73, // 10B73..10B77; UNKNOWN + 0x10B78, // 10B78..10B7F; INSCRIPTIONAL_PAHLAVI + 0x10B80, // 10B80..10B91; PSALTER_PAHLAVI + 0x10B92, // 10B92..10B98; UNKNOWN + 0x10B99, // 10B99..10B9C; PSALTER_PAHLAVI + 0x10B9D, // 10B9D..10BA8; UNKNOWN + 0x10BA9, // 10BA9..10BAF; PSALTER_PAHLAVI + 0x10BB0, // 10BB0..10BFF; UNKNOWN + 0x10C00, // 10C00..10C48; OLD_TURKIC + 0x10C49, // 10C49..10E5F; UNKNOWN + 0x10E60, // 10E60..10E7E; ARABIC + 0x10E7F, // 10E7F..10FFF; UNKNOWN + 0x11000, // 11000..1104D; BRAHMI + 0x1104E, // 1104E..11051; UNKNOWN + 0x11052, // 11052..1106F; BRAHMI + 0x11070, // 11070..1107E; UNKNOWN + 0x1107F, // 1107F ; BRAHMI + 0x11080, // 11080..110C1; KAITHI + 0x110C2, // 110C2..110CF; UNKNOWN + 0x110D0, // 110D0..110E8; SORA_SOMPENG + 0x110E9, // 110E9..110EF; UNKNOWN + 0x110F0, // 110F0..110F9; SORA_SOMPENG + 0x110FA, // 110FA..110FF; UNKNOWN + 0x11100, // 11100..11134; CHAKMA + 0x11135, // 11135 ; UNKNOWN + 0x11136, // 11136..11143; CHAKMA + 0x11144, // 11144..1114F; UNKNOWN + 0x11150, // 11150..11176; MAHAJANI + 0x11177, // 11177..1117F; UNKNOWN + 0x11180, // 11180..111C8; SHARADA + 0x111C9, // 111C9..111CC; UNKNOWN + 0x111CD, // 111CD ; SHARADA + 0x111CE, // 111CE..111CF; UNKNOWN + 0x111D0, // 111D0..111DA; SHARADA + 0x111DB, // 111DB..111E0; UNKNOWN + 0x111E1, // 111E1..111F4; SINHALA + 0x111F5, // 111F5..111FF; UNKNOWN + 0x11200, // 11200..11211; KHOJKI + 0x11212, // 11212 ; UNKNOWN + 0x11213, // 11213..1123D; KHOJKI + 0x1123E, // 1123E..112AF; UNKNOWN + 0x112B0, // 112B0..112EA; KHUDAWADI + 0x112EB, // 112EB..112EF; UNKNOWN + 0x112F0, // 112F0..112F9; KHUDAWADI + 0x112FA, // 112FA..11300; UNKNOWN + 0x11301, // 11301..11303; GRANTHA + 0x11304, // 11304 ; UNKNOWN + 0x11305, // 11305..1130C; GRANTHA + 0x1130D, // 1130D..1130E; UNKNOWN + 0x1130F, // 1130F..11310; GRANTHA + 0x11311, // 11311..11312; UNKNOWN + 0x11313, // 11313..11328; GRANTHA + 0x11329, // 11329 ; UNKNOWN + 0x1132A, // 1132A..11330; GRANTHA + 0x11331, // 11331 ; UNKNOWN + 0x11332, // 11332..11333; GRANTHA + 0x11334, // 11334 ; UNKNOWN + 0x11335, // 11335..11339; GRANTHA + 0x1133A, // 1133A..1133B; UNKNOWN + 0x1133C, // 1133C..11344; GRANTHA + 0x11345, // 11345..11346; UNKNOWN + 0x11347, // 11347..11348; GRANTHA + 0x11349, // 11349..1134A; UNKNOWN + 0x1134B, // 1134B..1134D; GRANTHA + 0x1134E, // 1134E..11356; UNKNOWN + 0x11357, // 11357 ; GRANTHA + 0x11358, // 11358..1135C; UNKNOWN + 0x1135D, // 1135D..11363; GRANTHA + 0x11364, // 11364..11365; UNKNOWN + 0x11366, // 11366..1136C; GRANTHA + 0x1136D, // 1136D..1136F; UNKNOWN + 0x11370, // 11370..11374; GRANTHA + 0x11375, // 11375..1147F; UNKNOWN + 0x11480, // 11480..114C7; TIRHUTA + 0x114C8, // 114C8..114CF; UNKNOWN + 0x114D0, // 114D0..114D9; TIRHUTA + 0x114DA, // 114DA..1157F; UNKNOWN + 0x11580, // 11580..115B5; SIDDHAM + 0x115B6, // 115B6..115B7; UNKNOWN + 0x115B8, // 115B8..115C9; SIDDHAM + 0x115CA, // 115CA..115FF; UNKNOWN + 0x11600, // 11600..11644; MODI + 0x11645, // 11645..1164F; UNKNOWN + 0x11650, // 11650..11659; MODI + 0x1165A, // 1165A..1167F; UNKNOWN + 0x11680, // 11680..116B7; TAKRI + 0x116B8, // 116B8..116BF; UNKNOWN + 0x116C0, // 116C0..116C9; TAKRI + 0x116CA, // 116CA..1189F; UNKNOWN + 0x118A0, // 118A0..118F2; WARANG_CITI + 0x118F3, // 118F3..118FE; UNKNOWN + 0x118FF, // 118FF ; WARANG_CITI + 0x11900, // 11900..11ABF; UNKNOWN + 0x11AC0, // 11AC0..11AF8; PAU_CIN_HAU + 0x11AF9, // 11AF9..11FFF; UNKNOWN + 0x12000, // 12000..12398; CUNEIFORM + 0x12399, // 12399..123FF; UNKNOWN + 0x12400, // 12400..1246E; CUNEIFORM + 0x1246F, // 1246F ; UNKNOWN + 0x12470, // 12470..12474; CUNEIFORM + 0x12475, // 12475..12FFF; UNKNOWN + 0x13000, // 13000..1342E; EGYPTIAN_HIEROGLYPHS + 0x1342F, // 1342F..167FF; UNKNOWN 0x16800, // 16800..16A38; BAMUM - 0x16F00, // 16F00..16F9F; MIAO - 0x1B000, // 1B000..1B000; KATAKANA - 0x1B001, // 1B001..1CFFF; HIRAGANA - 0x1D000, // 1D000..1D166; COMMON + 0x16A39, // 16A39..16A3F; UNKNOWN + 0x16A40, // 16A40..16A5E; MRO + 0x16A5F, // 16A5F ; UNKNOWN + 0x16A60, // 16A60..16A69; MRO + 0x16A6A, // 16A6A..16A6D; UNKNOWN + 0x16A6E, // 16A6E..16A6F; MRO + 0x16A70, // 16A70..16ACF; UNKNOWN + 0x16AD0, // 16AD0..16AED; BASSA_VAH + 0x16AEE, // 16AEE..16AEF; UNKNOWN + 0x16AF0, // 16AF0..16AF5; BASSA_VAH + 0x16AF6, // 16AF6..16AFF; UNKNOWN + 0x16B00, // 16B00..16B45; PAHAWH_HMONG + 0x16B46, // 16B46..16B4F; UNKNOWN + 0x16B50, // 16B50..16B59; PAHAWH_HMONG + 0x16B5A, // 16B5A ; UNKNOWN + 0x16B5B, // 16B5B..16B61; PAHAWH_HMONG + 0x16B62, // 16B62 ; UNKNOWN + 0x16B63, // 16B63..16B77; PAHAWH_HMONG + 0x16B78, // 16B78..16B7C; UNKNOWN + 0x16B7D, // 16B7D..16B8F; PAHAWH_HMONG + 0x16B90, // 16B90..16EFF; UNKNOWN + 0x16F00, // 16F00..16F44; MIAO + 0x16F45, // 16F45..16F4F; UNKNOWN + 0x16F50, // 16F50..16F7E; MIAO + 0x16F7F, // 16F7F..16F8E; UNKNOWN + 0x16F8F, // 16F8F..16F9F; MIAO + 0x16FA0, // 16FA0..1AFFF; UNKNOWN + 0x1B000, // 1B000 ; KATAKANA + 0x1B001, // 1B001 ; HIRAGANA + 0x1B002, // 1B002..1BBFF; UNKNOWN + 0x1BC00, // 1BC00..1BC6A; DUPLOYAN + 0x1BC6B, // 1BC6B..1BC6F; UNKNOWN + 0x1BC70, // 1BC70..1BC7C; DUPLOYAN + 0x1BC7D, // 1BC7D..1BC7F; UNKNOWN + 0x1BC80, // 1BC80..1BC88; DUPLOYAN + 0x1BC89, // 1BC89..1BC8F; UNKNOWN + 0x1BC90, // 1BC90..1BC99; DUPLOYAN + 0x1BC9A, // 1BC9A..1BC9B; UNKNOWN + 0x1BC9C, // 1BC9C..1BC9F; DUPLOYAN + 0x1BCA0, // 1BCA0..1BCA3; COMMON + 0x1BCA4, // 1BCA4..1CFFF; UNKNOWN + 0x1D000, // 1D000..1D0F5; COMMON + 0x1D0F6, // 1D0F6..1D0FF; UNKNOWN + 0x1D100, // 1D100..1D126; COMMON + 0x1D127, // 1D127..1D128; UNKNOWN + 0x1D129, // 1D129..1D166; COMMON 0x1D167, // 1D167..1D169; INHERITED 0x1D16A, // 1D16A..1D17A; COMMON 0x1D17B, // 1D17B..1D182; INHERITED @@ -4022,354 +5420,1635 @@ class Character implements java.io.Serializable, Comparable<Character> { 0x1D185, // 1D185..1D18B; INHERITED 0x1D18C, // 1D18C..1D1A9; COMMON 0x1D1AA, // 1D1AA..1D1AD; INHERITED - 0x1D1AE, // 1D1AE..1D1FF; COMMON - 0x1D200, // 1D200..1D2FF; GREEK - 0x1D300, // 1D300..1EDFF; COMMON - 0x1EE00, // 1EE00..1EFFF; ARABIC - 0x1F000, // 1F000..1F1FF; COMMON - 0x1F200, // 1F200..1F200; HIRAGANA - 0x1F201, // 1F210..1FFFF; COMMON - 0x20000, // 20000..E0000; HAN - 0xE0001, // E0001..E00FF; COMMON + 0x1D1AE, // 1D1AE..1D1DD; COMMON + 0x1D1DE, // 1D1DE..1D1FF; UNKNOWN + 0x1D200, // 1D200..1D245; GREEK + 0x1D246, // 1D246..1D2FF; UNKNOWN + 0x1D300, // 1D300..1D356; COMMON + 0x1D357, // 1D357..1D35F; UNKNOWN + 0x1D360, // 1D360..1D371; COMMON + 0x1D372, // 1D372..1D3FF; UNKNOWN + 0x1D400, // 1D400..1D454; COMMON + 0x1D455, // 1D455 ; UNKNOWN + 0x1D456, // 1D456..1D49C; COMMON + 0x1D49D, // 1D49D ; UNKNOWN + 0x1D49E, // 1D49E..1D49F; COMMON + 0x1D4A0, // 1D4A0..1D4A1; UNKNOWN + 0x1D4A2, // 1D4A2 ; COMMON + 0x1D4A3, // 1D4A3..1D4A4; UNKNOWN + 0x1D4A5, // 1D4A5..1D4A6; COMMON + 0x1D4A7, // 1D4A7..1D4A8; UNKNOWN + 0x1D4A9, // 1D4A9..1D4AC; COMMON + 0x1D4AD, // 1D4AD ; UNKNOWN + 0x1D4AE, // 1D4AE..1D4B9; COMMON + 0x1D4BA, // 1D4BA ; UNKNOWN + 0x1D4BB, // 1D4BB ; COMMON + 0x1D4BC, // 1D4BC ; UNKNOWN + 0x1D4BD, // 1D4BD..1D4C3; COMMON + 0x1D4C4, // 1D4C4 ; UNKNOWN + 0x1D4C5, // 1D4C5..1D505; COMMON + 0x1D506, // 1D506 ; UNKNOWN + 0x1D507, // 1D507..1D50A; COMMON + 0x1D50B, // 1D50B..1D50C; UNKNOWN + 0x1D50D, // 1D50D..1D514; COMMON + 0x1D515, // 1D515 ; UNKNOWN + 0x1D516, // 1D516..1D51C; COMMON + 0x1D51D, // 1D51D ; UNKNOWN + 0x1D51E, // 1D51E..1D539; COMMON + 0x1D53A, // 1D53A ; UNKNOWN + 0x1D53B, // 1D53B..1D53E; COMMON + 0x1D53F, // 1D53F ; UNKNOWN + 0x1D540, // 1D540..1D544; COMMON + 0x1D545, // 1D545 ; UNKNOWN + 0x1D546, // 1D546 ; COMMON + 0x1D547, // 1D547..1D549; UNKNOWN + 0x1D54A, // 1D54A..1D550; COMMON + 0x1D551, // 1D551 ; UNKNOWN + 0x1D552, // 1D552..1D6A5; COMMON + 0x1D6A6, // 1D6A6..1D6A7; UNKNOWN + 0x1D6A8, // 1D6A8..1D7CB; COMMON + 0x1D7CC, // 1D7CC..1D7CD; UNKNOWN + 0x1D7CE, // 1D7CE..1D7FF; COMMON + 0x1D800, // 1D800..1E7FF; UNKNOWN + 0x1E800, // 1E800..1E8C4; MENDE_KIKAKUI + 0x1E8C5, // 1E8C5..1E8C6; UNKNOWN + 0x1E8C7, // 1E8C7..1E8D6; MENDE_KIKAKUI + 0x1E8D7, // 1E8D7..1EDFF; UNKNOWN + 0x1EE00, // 1EE00..1EE03; ARABIC + 0x1EE04, // 1EE04 ; UNKNOWN + 0x1EE05, // 1EE05..1EE1F; ARABIC + 0x1EE20, // 1EE20 ; UNKNOWN + 0x1EE21, // 1EE21..1EE22; ARABIC + 0x1EE23, // 1EE23 ; UNKNOWN + 0x1EE24, // 1EE24 ; ARABIC + 0x1EE25, // 1EE25..1EE26; UNKNOWN + 0x1EE27, // 1EE27 ; ARABIC + 0x1EE28, // 1EE28 ; UNKNOWN + 0x1EE29, // 1EE29..1EE32; ARABIC + 0x1EE33, // 1EE33 ; UNKNOWN + 0x1EE34, // 1EE34..1EE37; ARABIC + 0x1EE38, // 1EE38 ; UNKNOWN + 0x1EE39, // 1EE39 ; ARABIC + 0x1EE3A, // 1EE3A ; UNKNOWN + 0x1EE3B, // 1EE3B ; ARABIC + 0x1EE3C, // 1EE3C..1EE41; UNKNOWN + 0x1EE42, // 1EE42 ; ARABIC + 0x1EE43, // 1EE43..1EE46; UNKNOWN + 0x1EE47, // 1EE47 ; ARABIC + 0x1EE48, // 1EE48 ; UNKNOWN + 0x1EE49, // 1EE49 ; ARABIC + 0x1EE4A, // 1EE4A ; UNKNOWN + 0x1EE4B, // 1EE4B ; ARABIC + 0x1EE4C, // 1EE4C ; UNKNOWN + 0x1EE4D, // 1EE4D..1EE4F; ARABIC + 0x1EE50, // 1EE50 ; UNKNOWN + 0x1EE51, // 1EE51..1EE52; ARABIC + 0x1EE53, // 1EE53 ; UNKNOWN + 0x1EE54, // 1EE54 ; ARABIC + 0x1EE55, // 1EE55..1EE56; UNKNOWN + 0x1EE57, // 1EE57 ; ARABIC + 0x1EE58, // 1EE58 ; UNKNOWN + 0x1EE59, // 1EE59 ; ARABIC + 0x1EE5A, // 1EE5A ; UNKNOWN + 0x1EE5B, // 1EE5B ; ARABIC + 0x1EE5C, // 1EE5C ; UNKNOWN + 0x1EE5D, // 1EE5D ; ARABIC + 0x1EE5E, // 1EE5E ; UNKNOWN + 0x1EE5F, // 1EE5F ; ARABIC + 0x1EE60, // 1EE60 ; UNKNOWN + 0x1EE61, // 1EE61..1EE62; ARABIC + 0x1EE63, // 1EE63 ; UNKNOWN + 0x1EE64, // 1EE64 ; ARABIC + 0x1EE65, // 1EE65..1EE66; UNKNOWN + 0x1EE67, // 1EE67..1EE6A; ARABIC + 0x1EE6B, // 1EE6B ; UNKNOWN + 0x1EE6C, // 1EE6C..1EE72; ARABIC + 0x1EE73, // 1EE73 ; UNKNOWN + 0x1EE74, // 1EE74..1EE77; ARABIC + 0x1EE78, // 1EE78 ; UNKNOWN + 0x1EE79, // 1EE79..1EE7C; ARABIC + 0x1EE7D, // 1EE7D ; UNKNOWN + 0x1EE7E, // 1EE7E ; ARABIC + 0x1EE7F, // 1EE7F ; UNKNOWN + 0x1EE80, // 1EE80..1EE89; ARABIC + 0x1EE8A, // 1EE8A ; UNKNOWN + 0x1EE8B, // 1EE8B..1EE9B; ARABIC + 0x1EE9C, // 1EE9C..1EEA0; UNKNOWN + 0x1EEA1, // 1EEA1..1EEA3; ARABIC + 0x1EEA4, // 1EEA4 ; UNKNOWN + 0x1EEA5, // 1EEA5..1EEA9; ARABIC + 0x1EEAA, // 1EEAA ; UNKNOWN + 0x1EEAB, // 1EEAB..1EEBB; ARABIC + 0x1EEBC, // 1EEBC..1EEEF; UNKNOWN + 0x1EEF0, // 1EEF0..1EEF1; ARABIC + 0x1EEF2, // 1EEF2..1EFFF; UNKNOWN + 0x1F000, // 1F000..1F02B; COMMON + 0x1F02C, // 1F02C..1F02F; UNKNOWN + 0x1F030, // 1F030..1F093; COMMON + 0x1F094, // 1F094..1F09F; UNKNOWN + 0x1F0A0, // 1F0A0..1F0AE; COMMON + 0x1F0AF, // 1F0AF..1F0B0; UNKNOWN + 0x1F0B1, // 1F0B1..1F0BF; COMMON + 0x1F0C0, // 1F0C0 ; UNKNOWN + 0x1F0C1, // 1F0C1..1F0CF; COMMON + 0x1F0D0, // 1F0D0 ; UNKNOWN + 0x1F0D1, // 1F0D1..1F0F5; COMMON + 0x1F0F6, // 1F0F6..1F0FF; UNKNOWN + 0x1F100, // 1F100..1F10C; COMMON + 0x1F10D, // 1F10D..1F10F; UNKNOWN + 0x1F110, // 1F110..1F12E; COMMON + 0x1F12F, // 1F12F ; UNKNOWN + 0x1F130, // 1F130..1F16B; COMMON + 0x1F16C, // 1F16C..1F16F; UNKNOWN + 0x1F170, // 1F170..1F19A; COMMON + 0x1F19B, // 1F19B..1F1E5; UNKNOWN + 0x1F1E6, // 1F1E6..1F1FF; COMMON + 0x1F200, // 1F200 ; HIRAGANA + 0x1F201, // 1F201..1F202; COMMON + 0x1F203, // 1F203..1F20F; UNKNOWN + 0x1F210, // 1F210..1F23A; COMMON + 0x1F23B, // 1F23B..1F23F; UNKNOWN + 0x1F240, // 1F240..1F248; COMMON + 0x1F249, // 1F249..1F24F; UNKNOWN + 0x1F250, // 1F250..1F251; COMMON + 0x1F252, // 1F252..1F2FF; UNKNOWN + 0x1F300, // 1F300..1F32C; COMMON + 0x1F32D, // 1F32D..1F32F; UNKNOWN + 0x1F330, // 1F330..1F37D; COMMON + 0x1F37E, // 1F37E..1F37F; UNKNOWN + 0x1F380, // 1F380..1F3CE; COMMON + 0x1F3CF, // 1F3CF..1F3D3; UNKNOWN + 0x1F3D4, // 1F3D4..1F3F7; COMMON + 0x1F3F8, // 1F3F8..1F3FF; UNKNOWN + 0x1F400, // 1F400..1F4FE; COMMON + 0x1F4FF, // 1F4FF ; UNKNOWN + 0x1F500, // 1F500..1F54A; COMMON + 0x1F54B, // 1F54B..1F54F; UNKNOWN + 0x1F550, // 1F550..1F579; COMMON + 0x1F57A, // 1F57A ; UNKNOWN + 0x1F57B, // 1F57B..1F5A3; COMMON + 0x1F5A4, // 1F5A4 ; UNKNOWN + 0x1F5A5, // 1F5A5..1F642; COMMON + 0x1F643, // 1F643..1F644; UNKNOWN + 0x1F645, // 1F645..1F6CF; COMMON + 0x1F6D0, // 1F6D0..1F6DF; UNKNOWN + 0x1F6E0, // 1F6E0..1F6EC; COMMON + 0x1F6ED, // 1F6ED..1F6EF; UNKNOWN + 0x1F6F0, // 1F6F0..1F6F3; COMMON + 0x1F6F4, // 1F6F4..1F6FF; UNKNOWN + 0x1F700, // 1F700..1F773; COMMON + 0x1F774, // 1F774..1F77F; UNKNOWN + 0x1F780, // 1F780..1F7D4; COMMON + 0x1F7D5, // 1F7D5..1F7FF; UNKNOWN + 0x1F800, // 1F800..1F80B; COMMON + 0x1F80C, // 1F80C..1F80F; UNKNOWN + 0x1F810, // 1F810..1F847; COMMON + 0x1F848, // 1F848..1F84F; UNKNOWN + 0x1F850, // 1F850..1F859; COMMON + 0x1F85A, // 1F85A..1F85F; UNKNOWN + 0x1F860, // 1F860..1F887; COMMON + 0x1F888, // 1F888..1F88F; UNKNOWN + 0x1F890, // 1F890..1F8AD; COMMON + 0x1F8AE, // 1F8AE..1FFFF; UNKNOWN + 0x20000, // 20000..2A6D6; HAN + 0x2A6D7, // 2A6D7..2A6FF; UNKNOWN + 0x2A700, // 2A700..2B734; HAN + 0x2B735, // 2B735..2B73F; UNKNOWN + 0x2B740, // 2B740..2B81D; HAN + 0x2B81E, // 2B81E..2F7FF; UNKNOWN + 0x2F800, // 2F800..2FA1D; HAN + 0x2FA1E, // 2FA1E..E0000; UNKNOWN + 0xE0001, // E0001 ; COMMON + 0xE0002, // E0002..E001F; UNKNOWN + 0xE0020, // E0020..E007F; COMMON + 0xE0080, // E0080..E00FF; UNKNOWN 0xE0100, // E0100..E01EF; INHERITED 0xE01F0 // E01F0..10FFFF; UNKNOWN - }; private static final UnicodeScript[] scripts = { - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - BOPOMOFO, - COMMON, - INHERITED, - GREEK, - COMMON, - GREEK, - COMMON, - GREEK, - COMMON, - GREEK, - COMMON, - GREEK, - COPTIC, - GREEK, - CYRILLIC, - INHERITED, - CYRILLIC, - ARMENIAN, - COMMON, - ARMENIAN, - HEBREW, - ARABIC, - COMMON, - ARABIC, - COMMON, - ARABIC, - COMMON, - ARABIC, - COMMON, - ARABIC, - INHERITED, - ARABIC, - COMMON, - ARABIC, - INHERITED, - ARABIC, - COMMON, - ARABIC, - SYRIAC, - ARABIC, - THAANA, - NKO, - SAMARITAN, - MANDAIC, - ARABIC, - DEVANAGARI, - INHERITED, - DEVANAGARI, - COMMON, - DEVANAGARI, - BENGALI, - GURMUKHI, - GUJARATI, - ORIYA, - TAMIL, - TELUGU, - KANNADA, - MALAYALAM, - SINHALA, - THAI, - COMMON, - THAI, - LAO, - TIBETAN, - COMMON, - TIBETAN, - MYANMAR, - GEORGIAN, - COMMON, - GEORGIAN, - HANGUL, - ETHIOPIC, - CHEROKEE, - CANADIAN_ABORIGINAL, - OGHAM, - RUNIC, - COMMON, - RUNIC, - TAGALOG, - HANUNOO, - COMMON, - BUHID, - TAGBANWA, - KHMER, - MONGOLIAN, - COMMON, - MONGOLIAN, - COMMON, - MONGOLIAN, - CANADIAN_ABORIGINAL, - LIMBU, - TAI_LE, - NEW_TAI_LUE, - KHMER, - BUGINESE, - TAI_THAM, - BALINESE, - SUNDANESE, - BATAK, - LEPCHA, - OL_CHIKI, - SUNDANESE, - INHERITED, - COMMON, - INHERITED, - COMMON, - INHERITED, - COMMON, - INHERITED, - COMMON, - INHERITED, - COMMON, - LATIN, - GREEK, - CYRILLIC, - LATIN, - GREEK, - LATIN, - GREEK, - LATIN, - CYRILLIC, - LATIN, - GREEK, - INHERITED, - LATIN, - GREEK, - COMMON, - INHERITED, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - INHERITED, - COMMON, - GREEK, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - BRAILLE, - COMMON, - GLAGOLITIC, - LATIN, - COPTIC, - GEORGIAN, - TIFINAGH, - ETHIOPIC, - CYRILLIC, - COMMON, - HAN, - COMMON, - HAN, - COMMON, - HAN, - COMMON, - HAN, - INHERITED, - HANGUL, - COMMON, - HAN, - COMMON, - HIRAGANA, - INHERITED, - COMMON, - HIRAGANA, - COMMON, - KATAKANA, - COMMON, - KATAKANA, - BOPOMOFO, - HANGUL, - COMMON, - BOPOMOFO, - COMMON, - KATAKANA, - HANGUL, - COMMON, - HANGUL, - COMMON, - KATAKANA, - COMMON, - HAN, - COMMON, - HAN, - YI, - LISU, - VAI, - CYRILLIC, - BAMUM, - COMMON, - LATIN, - COMMON, - LATIN, - SYLOTI_NAGRI, - COMMON, - PHAGS_PA, - SAURASHTRA, - DEVANAGARI, - KAYAH_LI, - REJANG, - HANGUL, - JAVANESE, - CHAM, - MYANMAR, - TAI_VIET, - MEETEI_MAYEK, - ETHIOPIC, - MEETEI_MAYEK, - HANGUL, - UNKNOWN , - HAN, - LATIN, - ARMENIAN, - HEBREW, - ARABIC, - COMMON, - ARABIC, - COMMON, - INHERITED, - COMMON, - INHERITED, - COMMON, - ARABIC, - COMMON, - LATIN, - COMMON, - LATIN, - COMMON, - KATAKANA, - COMMON, - KATAKANA, - COMMON, - HANGUL, - COMMON, - LINEAR_B, - COMMON, - GREEK, - COMMON, - INHERITED, - LYCIAN, - CARIAN, - OLD_ITALIC, - GOTHIC, - UGARITIC, - OLD_PERSIAN, - DESERET, - SHAVIAN, - OSMANYA, - CYPRIOT, - IMPERIAL_ARAMAIC, - PHOENICIAN, - LYDIAN, - MEROITIC_HIEROGLYPHS, - MEROITIC_CURSIVE, - KHAROSHTHI, - OLD_SOUTH_ARABIAN, - AVESTAN, - INSCRIPTIONAL_PARTHIAN, - INSCRIPTIONAL_PAHLAVI, - OLD_TURKIC, - ARABIC, - BRAHMI, - KAITHI, - SORA_SOMPENG, - CHAKMA, - SHARADA, - TAKRI, - CUNEIFORM, - EGYPTIAN_HIEROGLYPHS, - BAMUM, - MIAO, - KATAKANA, - HIRAGANA, - COMMON, - INHERITED, - COMMON, - INHERITED, - COMMON, - INHERITED, - COMMON, - INHERITED, - COMMON, - GREEK, - COMMON, - ARABIC, - COMMON, - HIRAGANA, - COMMON, - HAN, - COMMON, - INHERITED, - UNKNOWN + COMMON, // 0000..0040 + LATIN, // 0041..005A + COMMON, // 005B..0060 + LATIN, // 0061..007A + COMMON, // 007B..00A9 + LATIN, // 00AA + COMMON, // 00AB..00B9 + LATIN, // 00BA + COMMON, // 00BB..00BF + LATIN, // 00C0..00D6 + COMMON, // 00D7 + LATIN, // 00D8..00F6 + COMMON, // 00F7 + LATIN, // 00F8..02B8 + COMMON, // 02B9..02DF + LATIN, // 02E0..02E4 + COMMON, // 02E5..02E9 + BOPOMOFO, // 02EA..02EB + COMMON, // 02EC..02FF + INHERITED, // 0300..036F + GREEK, // 0370..0373 + COMMON, // 0374 + GREEK, // 0375..0377 + UNKNOWN, // 0378..0379 + GREEK, // 037A..037D + COMMON, // 037E + GREEK, // 037F + UNKNOWN, // 0380..0383 + GREEK, // 0384 + COMMON, // 0385 + GREEK, // 0386 + COMMON, // 0387 + GREEK, // 0388..038A + UNKNOWN, // 038B + GREEK, // 038C + UNKNOWN, // 038D + GREEK, // 038E..03A1 + UNKNOWN, // 03A2 + GREEK, // 03A3..03E1 + COPTIC, // 03E2..03EF + GREEK, // 03F0..03FF + CYRILLIC, // 0400..0484 + INHERITED, // 0485..0486 + CYRILLIC, // 0487..052F + UNKNOWN, // 0530 + ARMENIAN, // 0531..0556 + UNKNOWN, // 0557..0558 + ARMENIAN, // 0559..055F + UNKNOWN, // 0560 + ARMENIAN, // 0561..0587 + UNKNOWN, // 0588 + COMMON, // 0589 + ARMENIAN, // 058A + UNKNOWN, // 058B..058C + ARMENIAN, // 058D..058F + UNKNOWN, // 0590 + HEBREW, // 0591..05C7 + UNKNOWN, // 05C8..05CF + HEBREW, // 05D0..05EA + UNKNOWN, // 05EB..05EF + HEBREW, // 05F0..05F4 + UNKNOWN, // 05F5..05FF + ARABIC, // 0600..0604 + COMMON, // 0605 + ARABIC, // 0606..060B + COMMON, // 060C + ARABIC, // 060D..061A + COMMON, // 061B..061C + UNKNOWN, // 061D + ARABIC, // 061E + COMMON, // 061F + ARABIC, // 0620..063F + COMMON, // 0640 + ARABIC, // 0641..064A + INHERITED, // 064B..0655 + ARABIC, // 0656..065F + COMMON, // 0660..0669 + ARABIC, // 066A..066F + INHERITED, // 0670 + ARABIC, // 0671..06DC + COMMON, // 06DD + ARABIC, // 06DE..06FF + SYRIAC, // 0700..070D + UNKNOWN, // 070E + SYRIAC, // 070F..074A + UNKNOWN, // 074B..074C + SYRIAC, // 074D..074F + ARABIC, // 0750..077F + THAANA, // 0780..07B1 + UNKNOWN, // 07B2..07BF + NKO, // 07C0..07FA + UNKNOWN, // 07FB..07FF + SAMARITAN, // 0800..082D + UNKNOWN, // 082E..082F + SAMARITAN, // 0830..083E + UNKNOWN, // 083F + MANDAIC, // 0840..085B + UNKNOWN, // 085C..085D + MANDAIC, // 085E + UNKNOWN, // 085F..089F + ARABIC, // 08A0..08B2 + UNKNOWN, // 08B3..08E3 + ARABIC, // 08E4..08FF + DEVANAGARI, // 0900..0950 + INHERITED, // 0951..0952 + DEVANAGARI, // 0953..0963 + COMMON, // 0964..0965 + DEVANAGARI, // 0966..097F + BENGALI, // 0980..0983 + UNKNOWN, // 0984 + BENGALI, // 0985..098C + UNKNOWN, // 098D..098E + BENGALI, // 098F..0990 + UNKNOWN, // 0991..0992 + BENGALI, // 0993..09A8 + UNKNOWN, // 09A9 + BENGALI, // 09AA..09B0 + UNKNOWN, // 09B1 + BENGALI, // 09B2 + UNKNOWN, // 09B3..09B5 + BENGALI, // 09B6..09B9 + UNKNOWN, // 09BA..09BB + BENGALI, // 09BC..09C4 + UNKNOWN, // 09C5..09C6 + BENGALI, // 09C7..09C8 + UNKNOWN, // 09C9..09CA + BENGALI, // 09CB..09CE + UNKNOWN, // 09CF..09D6 + BENGALI, // 09D7 + UNKNOWN, // 09D8..09DB + BENGALI, // 09DC..09DD + UNKNOWN, // 09DE + BENGALI, // 09DF..09E3 + UNKNOWN, // 09E4..09E5 + BENGALI, // 09E6..09FB + UNKNOWN, // 09FC..0A00 + GURMUKHI, // 0A01..0A03 + UNKNOWN, // 0A04 + GURMUKHI, // 0A05..0A0A + UNKNOWN, // 0A0B..0A0E + GURMUKHI, // 0A0F..0A10 + UNKNOWN, // 0A11..0A12 + GURMUKHI, // 0A13..0A28 + UNKNOWN, // 0A29 + GURMUKHI, // 0A2A..0A30 + UNKNOWN, // 0A31 + GURMUKHI, // 0A32..0A33 + UNKNOWN, // 0A34 + GURMUKHI, // 0A35..0A36 + UNKNOWN, // 0A37 + GURMUKHI, // 0A38..0A39 + UNKNOWN, // 0A3A..0A3B + GURMUKHI, // 0A3C + UNKNOWN, // 0A3D + GURMUKHI, // 0A3E..0A42 + UNKNOWN, // 0A43..0A46 + GURMUKHI, // 0A47..0A48 + UNKNOWN, // 0A49..0A4A + GURMUKHI, // 0A4B..0A4D + UNKNOWN, // 0A4E..0A50 + GURMUKHI, // 0A51 + UNKNOWN, // 0A52..0A58 + GURMUKHI, // 0A59..0A5C + UNKNOWN, // 0A5D + GURMUKHI, // 0A5E + UNKNOWN, // 0A5F..0A65 + GURMUKHI, // 0A66..0A75 + UNKNOWN, // 0A76..0A80 + GUJARATI, // 0A81..0A83 + UNKNOWN, // 0A84 + GUJARATI, // 0A85..0A8D + UNKNOWN, // 0A8E + GUJARATI, // 0A8F..0A91 + UNKNOWN, // 0A92 + GUJARATI, // 0A93..0AA8 + UNKNOWN, // 0AA9 + GUJARATI, // 0AAA..0AB0 + UNKNOWN, // 0AB1 + GUJARATI, // 0AB2..0AB3 + UNKNOWN, // 0AB4 + GUJARATI, // 0AB5..0AB9 + UNKNOWN, // 0ABA..0ABB + GUJARATI, // 0ABC..0AC5 + UNKNOWN, // 0AC6 + GUJARATI, // 0AC7..0AC9 + UNKNOWN, // 0ACA + GUJARATI, // 0ACB..0ACD + UNKNOWN, // 0ACE..0ACF + GUJARATI, // 0AD0 + UNKNOWN, // 0AD1..0ADF + GUJARATI, // 0AE0..0AE3 + UNKNOWN, // 0AE4..0AE5 + GUJARATI, // 0AE6..0AF1 + UNKNOWN, // 0AF2..0B00 + ORIYA, // 0B01..0B03 + UNKNOWN, // 0B04 + ORIYA, // 0B05..0B0C + UNKNOWN, // 0B0D..0B0E + ORIYA, // 0B0F..0B10 + UNKNOWN, // 0B11..0B12 + ORIYA, // 0B13..0B28 + UNKNOWN, // 0B29 + ORIYA, // 0B2A..0B30 + UNKNOWN, // 0B31 + ORIYA, // 0B32..0B33 + UNKNOWN, // 0B34 + ORIYA, // 0B35..0B39 + UNKNOWN, // 0B3A..0B3B + ORIYA, // 0B3C..0B44 + UNKNOWN, // 0B45..0B46 + ORIYA, // 0B47..0B48 + UNKNOWN, // 0B49..0B4A + ORIYA, // 0B4B..0B4D + UNKNOWN, // 0B4E..0B55 + ORIYA, // 0B56..0B57 + UNKNOWN, // 0B58..0B5B + ORIYA, // 0B5C..0B5D + UNKNOWN, // 0B5E + ORIYA, // 0B5F..0B63 + UNKNOWN, // 0B64..0B65 + ORIYA, // 0B66..0B77 + UNKNOWN, // 0B78..0B81 + TAMIL, // 0B82..0B83 + UNKNOWN, // 0B84 + TAMIL, // 0B85..0B8A + UNKNOWN, // 0B8B..0B8D + TAMIL, // 0B8E..0B90 + UNKNOWN, // 0B91 + TAMIL, // 0B92..0B95 + UNKNOWN, // 0B96..0B98 + TAMIL, // 0B99..0B9A + UNKNOWN, // 0B9B + TAMIL, // 0B9C + UNKNOWN, // 0B9D + TAMIL, // 0B9E..0B9F + UNKNOWN, // 0BA0..0BA2 + TAMIL, // 0BA3..0BA4 + UNKNOWN, // 0BA5..0BA7 + TAMIL, // 0BA8..0BAA + UNKNOWN, // 0BAB..0BAD + TAMIL, // 0BAE..0BB9 + UNKNOWN, // 0BBA..0BBD + TAMIL, // 0BBE..0BC2 + UNKNOWN, // 0BC3..0BC5 + TAMIL, // 0BC6..0BC8 + UNKNOWN, // 0BC9 + TAMIL, // 0BCA..0BCD + UNKNOWN, // 0BCE..0BCF + TAMIL, // 0BD0 + UNKNOWN, // 0BD1..0BD6 + TAMIL, // 0BD7 + UNKNOWN, // 0BD8..0BE5 + TAMIL, // 0BE6..0BFA + UNKNOWN, // 0BFB..0BFF + TELUGU, // 0C00..0C03 + UNKNOWN, // 0C04 + TELUGU, // 0C05..0C0C + UNKNOWN, // 0C0D + TELUGU, // 0C0E..0C10 + UNKNOWN, // 0C11 + TELUGU, // 0C12..0C28 + UNKNOWN, // 0C29 + TELUGU, // 0C2A..0C39 + UNKNOWN, // 0C3A..0C3C + TELUGU, // 0C3D..0C44 + UNKNOWN, // 0C45 + TELUGU, // 0C46..0C48 + UNKNOWN, // 0C49 + TELUGU, // 0C4A..0C4D + UNKNOWN, // 0C4E..0C54 + TELUGU, // 0C55..0C56 + UNKNOWN, // 0C57 + TELUGU, // 0C58..0C59 + UNKNOWN, // 0C5A..0C5F + TELUGU, // 0C60..0C63 + UNKNOWN, // 0C64..0C65 + TELUGU, // 0C66..0C6F + UNKNOWN, // 0C70..0C77 + TELUGU, // 0C78..0C7F + UNKNOWN, // 0C80 + KANNADA, // 0C81..0C83 + UNKNOWN, // 0C84 + KANNADA, // 0C85..0C8C + UNKNOWN, // 0C8D + KANNADA, // 0C8E..0C90 + UNKNOWN, // 0C91 + KANNADA, // 0C92..0CA8 + UNKNOWN, // 0CA9 + KANNADA, // 0CAA..0CB3 + UNKNOWN, // 0CB4 + KANNADA, // 0CB5..0CB9 + UNKNOWN, // 0CBA..0CBB + KANNADA, // 0CBC..0CC4 + UNKNOWN, // 0CC5 + KANNADA, // 0CC6..0CC8 + UNKNOWN, // 0CC9 + KANNADA, // 0CCA..0CCD + UNKNOWN, // 0CCE..0CD4 + KANNADA, // 0CD5..0CD6 + UNKNOWN, // 0CD7..0CDD + KANNADA, // 0CDE + UNKNOWN, // 0CDF + KANNADA, // 0CE0..0CE3 + UNKNOWN, // 0CE4..0CE5 + KANNADA, // 0CE6..0CEF + UNKNOWN, // 0CF0 + KANNADA, // 0CF1..0CF2 + UNKNOWN, // 0CF3..0D00 + MALAYALAM, // 0D01..0D03 + UNKNOWN, // 0D04 + MALAYALAM, // 0D05..0D0C + UNKNOWN, // 0D0D + MALAYALAM, // 0D0E..0D10 + UNKNOWN, // 0D11 + MALAYALAM, // 0D12..0D3A + UNKNOWN, // 0D3B..0D3C + MALAYALAM, // 0D3D..0D44 + UNKNOWN, // 0D45 + MALAYALAM, // 0D46..0D48 + UNKNOWN, // 0D49 + MALAYALAM, // 0D4A..0D4E + UNKNOWN, // 0D4F..0D56 + MALAYALAM, // 0D57 + UNKNOWN, // 0D58..0D5F + MALAYALAM, // 0D60..0D63 + UNKNOWN, // 0D64..0D65 + MALAYALAM, // 0D66..0D75 + UNKNOWN, // 0D76..0D78 + MALAYALAM, // 0D79..0D7F + UNKNOWN, // 0D80..0D81 + SINHALA, // 0D82..0D83 + UNKNOWN, // 0D84 + SINHALA, // 0D85..0D96 + UNKNOWN, // 0D97..0D99 + SINHALA, // 0D9A..0DB1 + UNKNOWN, // 0DB2 + SINHALA, // 0DB3..0DBB + UNKNOWN, // 0DBC + SINHALA, // 0DBD + UNKNOWN, // 0DBE..0DBF + SINHALA, // 0DC0..0DC6 + UNKNOWN, // 0DC7..0DC9 + SINHALA, // 0DCA + UNKNOWN, // 0DCB..0DCE + SINHALA, // 0DCF..0DD4 + UNKNOWN, // 0DD5 + SINHALA, // 0DD6 + UNKNOWN, // 0DD7 + SINHALA, // 0DD8..0DDF + UNKNOWN, // 0DE0..0DE5 + SINHALA, // 0DE6..0DEF + UNKNOWN, // 0DF0..0DF1 + SINHALA, // 0DF2..0DF4 + UNKNOWN, // 0DF5..0E00 + THAI, // 0E01..0E3A + UNKNOWN, // 0E3B..0E3E + COMMON, // 0E3F + THAI, // 0E40..0E5B + UNKNOWN, // 0E5C..0E80 + LAO, // 0E81..0E82 + UNKNOWN, // 0E83 + LAO, // 0E84 + UNKNOWN, // 0E85..0E86 + LAO, // 0E87..0E88 + UNKNOWN, // 0E89 + LAO, // 0E8A + UNKNOWN, // 0E8B..0E8C + LAO, // 0E8D + UNKNOWN, // 0E8E..0E93 + LAO, // 0E94..0E97 + UNKNOWN, // 0E98 + LAO, // 0E99..0E9F + UNKNOWN, // 0EA0 + LAO, // 0EA1..0EA3 + UNKNOWN, // 0EA4 + LAO, // 0EA5 + UNKNOWN, // 0EA6 + LAO, // 0EA7 + UNKNOWN, // 0EA8..0EA9 + LAO, // 0EAA..0EAB + UNKNOWN, // 0EAC + LAO, // 0EAD..0EB9 + UNKNOWN, // 0EBA + LAO, // 0EBB..0EBD + UNKNOWN, // 0EBE..0EBF + LAO, // 0EC0..0EC4 + UNKNOWN, // 0EC5 + LAO, // 0EC6 + UNKNOWN, // 0EC7 + LAO, // 0EC8..0ECD + UNKNOWN, // 0ECE..0ECF + LAO, // 0ED0..0ED9 + UNKNOWN, // 0EDA..0EDB + LAO, // 0EDC..0EDF + UNKNOWN, // 0EE0..0EFF + TIBETAN, // 0F00..0F47 + UNKNOWN, // 0F48 + TIBETAN, // 0F49..0F6C + UNKNOWN, // 0F6D..0F70 + TIBETAN, // 0F71..0F97 + UNKNOWN, // 0F98 + TIBETAN, // 0F99..0FBC + UNKNOWN, // 0FBD + TIBETAN, // 0FBE..0FCC + UNKNOWN, // 0FCD + TIBETAN, // 0FCE..0FD4 + COMMON, // 0FD5..0FD8 + TIBETAN, // 0FD9..0FDA + UNKNOWN, // 0FDB..FFF + MYANMAR, // 1000..109F + GEORGIAN, // 10A0..10C5 + UNKNOWN, // 10C6 + GEORGIAN, // 10C7 + UNKNOWN, // 10C8..10CC + GEORGIAN, // 10CD + UNKNOWN, // 10CE..10CF + GEORGIAN, // 10D0..10FA + COMMON, // 10FB + GEORGIAN, // 10FC..10FF + HANGUL, // 1100..11FF + ETHIOPIC, // 1200..1248 + UNKNOWN, // 1249 + ETHIOPIC, // 124A..124D + UNKNOWN, // 124E..124F + ETHIOPIC, // 1250..1256 + UNKNOWN, // 1257 + ETHIOPIC, // 1258 + UNKNOWN, // 1259 + ETHIOPIC, // 125A..125D + UNKNOWN, // 125E..125F + ETHIOPIC, // 1260..1288 + UNKNOWN, // 1289 + ETHIOPIC, // 128A..128D + UNKNOWN, // 128E..128F + ETHIOPIC, // 1290..12B0 + UNKNOWN, // 12B1 + ETHIOPIC, // 12B2..12B5 + UNKNOWN, // 12B6..12B7 + ETHIOPIC, // 12B8..12BE + UNKNOWN, // 12BF + ETHIOPIC, // 12C0 + UNKNOWN, // 12C1 + ETHIOPIC, // 12C2..12C5 + UNKNOWN, // 12C6..12C7 + ETHIOPIC, // 12C8..12D6 + UNKNOWN, // 12D7 + ETHIOPIC, // 12D8..1310 + UNKNOWN, // 1311 + ETHIOPIC, // 1312..1315 + UNKNOWN, // 1316..1317 + ETHIOPIC, // 1318..135A + UNKNOWN, // 135B..135C + ETHIOPIC, // 135D..137C + UNKNOWN, // 137D..137F + ETHIOPIC, // 1380..1399 + UNKNOWN, // 139A..139F + CHEROKEE, // 13A0..13F4 + UNKNOWN, // 13F5..13FF + CANADIAN_ABORIGINAL, // 1400..167F + OGHAM, // 1680..169C + UNKNOWN, // 169D..169F + RUNIC, // 16A0..16EA + COMMON, // 16EB..16ED + RUNIC, // 16EE..16F8 + UNKNOWN, // 16F9..16FF + TAGALOG, // 1700..170C + UNKNOWN, // 170D + TAGALOG, // 170E..1714 + UNKNOWN, // 1715..171F + HANUNOO, // 1720..1734 + COMMON, // 1735..1736 + UNKNOWN, // 1737..173F + BUHID, // 1740..1753 + UNKNOWN, // 1754..175F + TAGBANWA, // 1760..176C + UNKNOWN, // 176D + TAGBANWA, // 176E..1770 + UNKNOWN, // 1771 + TAGBANWA, // 1772..1773 + UNKNOWN, // 1774..177F + KHMER, // 1780..17DD + UNKNOWN, // 17DE..17DF + KHMER, // 17E0..17E9 + UNKNOWN, // 17EA..17EF + KHMER, // 17F0..17F9 + UNKNOWN, // 17FA..17FF + MONGOLIAN, // 1800..1801 + COMMON, // 1802..1803 + MONGOLIAN, // 1804 + COMMON, // 1805 + MONGOLIAN, // 1806..180E + UNKNOWN, // 180F + MONGOLIAN, // 1810..1819 + UNKNOWN, // 181A..181F + MONGOLIAN, // 1820..1877 + UNKNOWN, // 1878..187F + MONGOLIAN, // 1880..18AA + UNKNOWN, // 18AB..18AF + CANADIAN_ABORIGINAL, // 18B0..18F5 + UNKNOWN, // 18F6..18FF + LIMBU, // 1900..191E + UNKNOWN, // 191F + LIMBU, // 1920..192B + UNKNOWN, // 192C..192F + LIMBU, // 1930..193B + UNKNOWN, // 193C..193F + LIMBU, // 1940 + UNKNOWN, // 1941..1943 + LIMBU, // 1944..194F + TAI_LE, // 1950..196D + UNKNOWN, // 196E..196F + TAI_LE, // 1970..1974 + UNKNOWN, // 1975..197F + NEW_TAI_LUE, // 1980..19AB + UNKNOWN, // 19AC..19AF + NEW_TAI_LUE, // 19B0..19C9 + UNKNOWN, // 19CA..19CF + NEW_TAI_LUE, // 19D0..19DA + UNKNOWN, // 19DB..19DD + NEW_TAI_LUE, // 19DE..19DF + KHMER, // 19E0..19FF + BUGINESE, // 1A00..1A1B + UNKNOWN, // 1A1C..1A1D + BUGINESE, // 1A1E..1A1F + TAI_THAM, // 1A20..1A5E + UNKNOWN, // 1A5F + TAI_THAM, // 1A60..1A7C + UNKNOWN, // 1A7D..1A7E + TAI_THAM, // 1A7F..1A89 + UNKNOWN, // 1A8A..1A8F + TAI_THAM, // 1A90..1A99 + UNKNOWN, // 1A9A..1A9F + TAI_THAM, // 1AA0..1AAD + UNKNOWN, // 1AAE..1AAF + INHERITED, // 1AB0..1ABE + UNKNOWN, // 1ABF..1AFF + BALINESE, // 1B00..1B4B + UNKNOWN, // 1B4C..1B4F + BALINESE, // 1B50..1B7C + UNKNOWN, // 1B7D..1B7F + SUNDANESE, // 1B80..1BBF + BATAK, // 1BC0..1BF3 + UNKNOWN, // 1BF4..1BFB + BATAK, // 1BFC..1BFF + LEPCHA, // 1C00..1C37 + UNKNOWN, // 1C38..1C3A + LEPCHA, // 1C3B..1C49 + UNKNOWN, // 1C4A..1C4C + LEPCHA, // 1C4D..1C4F + OL_CHIKI, // 1C50..1C7F + UNKNOWN, // 1C80..1CBF + SUNDANESE, // 1CC0..1CC7 + UNKNOWN, // 1CC8..1CCF + INHERITED, // 1CD0..1CD2 + COMMON, // 1CD3 + INHERITED, // 1CD4..1CE0 + COMMON, // 1CE1 + INHERITED, // 1CE2..1CE8 + COMMON, // 1CE9..1CEC + INHERITED, // 1CED + COMMON, // 1CEE..1CF3 + INHERITED, // 1CF4 + COMMON, // 1CF5..1CF6 + UNKNOWN, // 1CF7 + INHERITED, // 1CF8..1CF9 + UNKNOWN, // 1CFA..1CFF + LATIN, // 1D00..1D25 + GREEK, // 1D26..1D2A + CYRILLIC, // 1D2B + LATIN, // 1D2C..1D5C + GREEK, // 1D5D..1D61 + LATIN, // 1D62..1D65 + GREEK, // 1D66..1D6A + LATIN, // 1D6B..1D77 + CYRILLIC, // 1D78 + LATIN, // 1D79..1DBE + GREEK, // 1DBF + INHERITED, // 1DC0..1DF5 + UNKNOWN, // 1DF6..1DFB + INHERITED, // 1DFC..1DFF + LATIN, // 1E00..1EFF + GREEK, // 1F00..1F15 + UNKNOWN, // 1F16..1F17 + GREEK, // 1F18..1F1D + UNKNOWN, // 1F1E..1F1F + GREEK, // 1F20..1F45 + UNKNOWN, // 1F46..1F47 + GREEK, // 1F48..1F4D + UNKNOWN, // 1F4E..1F4F + GREEK, // 1F50..1F57 + UNKNOWN, // 1F58 + GREEK, // 1F59 + UNKNOWN, // 1F5A + GREEK, // 1F5B + UNKNOWN, // 1F5C + GREEK, // 1F5D + UNKNOWN, // 1F5E + GREEK, // 1F5F..1F7D + UNKNOWN, // 1F7E..1F7F + GREEK, // 1F80..1FB4 + UNKNOWN, // 1FB5 + GREEK, // 1FB6..1FC4 + UNKNOWN, // 1FC5 + GREEK, // 1FC6..1FD3 + UNKNOWN, // 1FD4..1FD5 + GREEK, // 1FD6..1FDB + UNKNOWN, // 1FDC + GREEK, // 1FDD..1FEF + UNKNOWN, // 1FF0..1FF1 + GREEK, // 1FF2..1FF4 + UNKNOWN, // 1FF5 + GREEK, // 1FF6..1FFE + UNKNOWN, // 1FFF + COMMON, // 2000..200B + INHERITED, // 200C..200D + COMMON, // 200E..2064 + UNKNOWN, // 2065 + COMMON, // 2066..2070 + LATIN, // 2071 + UNKNOWN, // 2072..2073 + COMMON, // 2074..207E + LATIN, // 207F + COMMON, // 2080..208E + UNKNOWN, // 208F + LATIN, // 2090..209C + UNKNOWN, // 209D..209F + COMMON, // 20A0..20BD + UNKNOWN, // 20BE..20CF + INHERITED, // 20D0..20F0 + UNKNOWN, // 20F1..20FF + COMMON, // 2100..2125 + GREEK, // 2126 + COMMON, // 2127..2129 + LATIN, // 212A..212B + COMMON, // 212C..2131 + LATIN, // 2132 + COMMON, // 2133..214D + LATIN, // 214E + COMMON, // 214F..215F + LATIN, // 2160..2188 + COMMON, // 2189 + UNKNOWN, // 218A..218F + COMMON, // 2190..23FA + UNKNOWN, // 23FB..23FF + COMMON, // 2400..2426 + UNKNOWN, // 2427..243F + COMMON, // 2440..244A + UNKNOWN, // 244B..245F + COMMON, // 2460..27FF + BRAILLE, // 2800..28FF + COMMON, // 2900..2B73 + UNKNOWN, // 2B74..2B75 + COMMON, // 2B76..2B95 + UNKNOWN, // 2B96..2B97 + COMMON, // 2B98..2BB9 + UNKNOWN, // 2BBA..2BBC + COMMON, // 2BBD..2BC8 + UNKNOWN, // 2BC9 + COMMON, // 2BCA..2BD1 + UNKNOWN, // 2BD2..2BFF + GLAGOLITIC, // 2C00..2C2E + UNKNOWN, // 2C2F + GLAGOLITIC, // 2C30..2C5E + UNKNOWN, // 2C5F + LATIN, // 2C60..2C7F + COPTIC, // 2C80..2CF3 + UNKNOWN, // 2CF4..2CF8 + COPTIC, // 2CF9..2CFF + GEORGIAN, // 2D00..2D25 + UNKNOWN, // 2D26 + GEORGIAN, // 2D27 + UNKNOWN, // 2D28..2D2C + GEORGIAN, // 2D2D + UNKNOWN, // 2D2E..2D2F + TIFINAGH, // 2D30..2D67 + UNKNOWN, // 2D68..2D6E + TIFINAGH, // 2D6F..2D70 + UNKNOWN, // 2D71..2D7E + TIFINAGH, // 2D7F + ETHIOPIC, // 2D80..2D96 + UNKNOWN, // 2D97..2D9F + ETHIOPIC, // 2DA0..2DA6 + UNKNOWN, // 2DA7 + ETHIOPIC, // 2DA8..2DAE + UNKNOWN, // 2DAF + ETHIOPIC, // 2DB0..2DB6 + UNKNOWN, // 2DB7 + ETHIOPIC, // 2DB8..2DBE + UNKNOWN, // 2DBF + ETHIOPIC, // 2DC0..2DC6 + UNKNOWN, // 2DC7 + ETHIOPIC, // 2DC8..2DCE + UNKNOWN, // 2DCF + ETHIOPIC, // 2DD0..2DD6 + UNKNOWN, // 2DD7 + ETHIOPIC, // 2DD8..2DDE + UNKNOWN, // 2DDF + CYRILLIC, // 2DE0..2DFF + COMMON, // 2E00..2E42 + UNKNOWN, // 2E43..2E7F + HAN, // 2E80..2E99 + UNKNOWN, // 2E9A + HAN, // 2E9B..2EF3 + UNKNOWN, // 2EF4..2EFF + HAN, // 2F00..2FD5 + UNKNOWN, // 2FD6..2FEF + COMMON, // 2FF0..2FFB + UNKNOWN, // 2FFC..2FFF + COMMON, // 3000..3004 + HAN, // 3005 + COMMON, // 3006 + HAN, // 3007 + COMMON, // 3008..3020 + HAN, // 3021..3029 + INHERITED, // 302A..302D + HANGUL, // 302E..302F + COMMON, // 3030..3037 + HAN, // 3038..303B + COMMON, // 303C..303F + UNKNOWN, // 3040 + HIRAGANA, // 3041..3096 + UNKNOWN, // 3097..3098 + INHERITED, // 3099..309A + COMMON, // 309B..309C + HIRAGANA, // 309D..309F + COMMON, // 30A0 + KATAKANA, // 30A1..30FA + COMMON, // 30FB..30FC + KATAKANA, // 30FD..30FF + UNKNOWN, // 3100..3104 + BOPOMOFO, // 3105..312D + UNKNOWN, // 312E..3130 + HANGUL, // 3131..318E + UNKNOWN, // 318F + COMMON, // 3190..319F + BOPOMOFO, // 31A0..31BA + UNKNOWN, // 31BB..31BF + COMMON, // 31C0..31E3 + UNKNOWN, // 31E4..31EF + KATAKANA, // 31F0..31FF + HANGUL, // 3200..321E + UNKNOWN, // 321F + COMMON, // 3220..325F + HANGUL, // 3260..327E + COMMON, // 327F..32CF + KATAKANA, // 32D0..32FE + UNKNOWN, // 32FF + KATAKANA, // 3300..3357 + COMMON, // 3358..33FF + HAN, // 3400..4DB5 + UNKNOWN, // 4DB6..4DBF + COMMON, // 4DC0..4DFF + HAN, // 4E00..9FCC + UNKNOWN, // 9FCD..9FFF + YI, // A000..A48C + UNKNOWN, // A48D..A48F + YI, // A490..A4C6 + UNKNOWN, // A4C7..A4CF + LISU, // A4D0..A4FF + VAI, // A500..A62B + UNKNOWN, // A62C..A63F + CYRILLIC, // A640..A69D + UNKNOWN, // A69E + CYRILLIC, // A69F + BAMUM, // A6A0..A6F7 + UNKNOWN, // A6F8..A6FF + COMMON, // A700..A721 + LATIN, // A722..A787 + COMMON, // A788..A78A + LATIN, // A78B..A78E + UNKNOWN, // A78F + LATIN, // A790..A7AD + UNKNOWN, // A7AE..A7AF + LATIN, // A7B0..A7B1 + UNKNOWN, // A7B2..A7F6 + LATIN, // A7F7..A7FF + SYLOTI_NAGRI, // A800..A82B + UNKNOWN, // A82C..A82F + COMMON, // A830..A839 + UNKNOWN, // A83A..A83F + PHAGS_PA, // A840..A877 + UNKNOWN, // A878..A87F + SAURASHTRA, // A880..A8C4 + UNKNOWN, // A8C5..A8CD + SAURASHTRA, // A8CE..A8D9 + UNKNOWN, // A8DA..A8DF + DEVANAGARI, // A8E0..A8FB + UNKNOWN, // A8FC..A8FF + KAYAH_LI, // A900..A92D + COMMON, // A92E + KAYAH_LI, // A92F + REJANG, // A930..A953 + UNKNOWN, // A954..A95E + REJANG, // A95F + HANGUL, // A960..A97C + UNKNOWN, // A97D..A97F + JAVANESE, // A980..A9CD + UNKNOWN, // A9CE + COMMON, // A9CF + JAVANESE, // A9D0..A9D9 + UNKNOWN, // A9DA..A9DD + JAVANESE, // A9DE..A9DF + MYANMAR, // A9E0..A9FE + UNKNOWN, // A9FF + CHAM, // AA00..AA36 + UNKNOWN, // AA37..AA3F + CHAM, // AA40..AA4D + UNKNOWN, // AA4E..AA4F + CHAM, // AA50..AA59 + UNKNOWN, // AA5A..AA5B + CHAM, // AA5C..AA5F + MYANMAR, // AA60..AA7F + TAI_VIET, // AA80..AAC2 + UNKNOWN, // AAC3..AADA + TAI_VIET, // AADB..AADF + MEETEI_MAYEK, // AAE0..AAF6 + UNKNOWN, // AAF7..AB00 + ETHIOPIC, // AB01..AB06 + UNKNOWN, // AB07..AB08 + ETHIOPIC, // AB09..AB0E + UNKNOWN, // AB0F..AB10 + ETHIOPIC, // AB11..AB16 + UNKNOWN, // AB17..AB1F + ETHIOPIC, // AB20..AB26 + UNKNOWN, // AB27 + ETHIOPIC, // AB28..AB2E + UNKNOWN, // AB2F + LATIN, // AB30..AB5A + COMMON, // AB5B + LATIN, // AB5C..AB5F + UNKNOWN, // AB60..AB63 + LATIN, // AB64 + GREEK, // AB65 + UNKNOWN, // AB66..ABBF + MEETEI_MAYEK, // ABC0..ABED + UNKNOWN, // ABEE..ABEF + MEETEI_MAYEK, // ABF0..ABF9 + UNKNOWN, // ABFA..ABFF + HANGUL, // AC00..D7A3 + UNKNOWN, // D7A4..D7AF + HANGUL, // D7B0..D7C6 + UNKNOWN, // D7C7..D7CA + HANGUL, // D7CB..D7FB + UNKNOWN, // D7FC..F8FF + HAN, // F900..FA6D + UNKNOWN, // FA6E..FA6F + HAN, // FA70..FAD9 + UNKNOWN, // FADA..FAFF + LATIN, // FB00..FB06 + UNKNOWN, // FB07..FB12 + ARMENIAN, // FB13..FB17 + UNKNOWN, // FB18..FB1C + HEBREW, // FB1D..FB36 + UNKNOWN, // FB37 + HEBREW, // FB38..FB3C + UNKNOWN, // FB3D + HEBREW, // FB3E + UNKNOWN, // FB3F + HEBREW, // FB40..FB41 + UNKNOWN, // FB42 + HEBREW, // FB43..FB44 + UNKNOWN, // FB45 + HEBREW, // FB46..FB4F + ARABIC, // FB50..FBC1 + UNKNOWN, // FBC2..FBD2 + ARABIC, // FBD3..FD3D + COMMON, // FD3E..FD3F + UNKNOWN, // FD40..FD4F + ARABIC, // FD50..FD8F + UNKNOWN, // FD90..FD91 + ARABIC, // FD92..FDC7 + UNKNOWN, // FDC8..FDEF + ARABIC, // FDF0..FDFD + UNKNOWN, // FDFE..FDFF + INHERITED, // FE00..FE0F + COMMON, // FE10..FE19 + UNKNOWN, // FE1A..FE1F + INHERITED, // FE20..FE2D + UNKNOWN, // FE2E..FE2F + COMMON, // FE30..FE52 + UNKNOWN, // FE53 + COMMON, // FE54..FE66 + UNKNOWN, // FE67 + COMMON, // FE68..FE6B + UNKNOWN, // FE6C..FE6F + ARABIC, // FE70..FE74 + UNKNOWN, // FE75 + ARABIC, // FE76..FEFC + UNKNOWN, // FEFD..FEFE + COMMON, // FEFF + UNKNOWN, // FF00 + COMMON, // FF01..FF20 + LATIN, // FF21..FF3A + COMMON, // FF3B..FF40 + LATIN, // FF41..FF5A + COMMON, // FF5B..FF65 + KATAKANA, // FF66..FF6F + COMMON, // FF70 + KATAKANA, // FF71..FF9D + COMMON, // FF9E..FF9F + HANGUL, // FFA0..FFBE + UNKNOWN, // FFBF..FFC1 + HANGUL, // FFC2..FFC7 + UNKNOWN, // FFC8..FFC9 + HANGUL, // FFCA..FFCF + UNKNOWN, // FFD0..FFD1 + HANGUL, // FFD2..FFD7 + UNKNOWN, // FFD8..FFD9 + HANGUL, // FFDA..FFDC + UNKNOWN, // FFDD..FFDF + COMMON, // FFE0..FFE6 + UNKNOWN, // FFE7 + COMMON, // FFE8..FFEE + UNKNOWN, // FFEF..FFF8 + COMMON, // FFF9..FFFD + UNKNOWN, // FFFE..FFFF + LINEAR_B, // 10000..1000B + UNKNOWN, // 1000C + LINEAR_B, // 1000D..10026 + UNKNOWN, // 10027 + LINEAR_B, // 10028..1003A + UNKNOWN, // 1003B + LINEAR_B, // 1003C..1003D + UNKNOWN, // 1003E + LINEAR_B, // 1003F..1004D + UNKNOWN, // 1004E..1004F + LINEAR_B, // 10050..1005D + UNKNOWN, // 1005E..1007F + LINEAR_B, // 10080..100FA + UNKNOWN, // 100FB..100FF + COMMON, // 10100..10102 + UNKNOWN, // 10103..10106 + COMMON, // 10107..10133 + UNKNOWN, // 10134..10136 + COMMON, // 10137..1013F + GREEK, // 10140..1018C + UNKNOWN, // 1018D..1018F + COMMON, // 10190..1019B + UNKNOWN, // 1019C..1019F + GREEK, // 101A0 + UNKNOWN, // 101A1..101CF + COMMON, // 101D0..101FC + INHERITED, // 101FD + UNKNOWN, // 101FE..1027F + LYCIAN, // 10280..1029C + UNKNOWN, // 1029D..1029F + CARIAN, // 102A0..102D0 + UNKNOWN, // 102D1..102DF + INHERITED, // 102E0 + COMMON, // 102E1..102FB + UNKNOWN, // 102FC..102FF + OLD_ITALIC, // 10300..10323 + UNKNOWN, // 10324..1032F + GOTHIC, // 10330..1034A + UNKNOWN, // 1034B..1034F + OLD_PERMIC, // 10350..1037A + UNKNOWN, // 1037B..1037F + UGARITIC, // 10380..1039D + UNKNOWN, // 1039E + UGARITIC, // 1039F + OLD_PERSIAN, // 103A0..103C3 + UNKNOWN, // 103C4..103C7 + OLD_PERSIAN, // 103C8..103D5 + UNKNOWN, // 103D6..103FF + DESERET, // 10400..1044F + SHAVIAN, // 10450..1047F + OSMANYA, // 10480..1049D + UNKNOWN, // 1049E..1049F + OSMANYA, // 104A0..104A9 + UNKNOWN, // 104AA..104FF + ELBASAN, // 10500..10527 + UNKNOWN, // 10528..1052F + CAUCASIAN_ALBANIAN, // 10530..10563 + UNKNOWN, // 10564..1056E + CAUCASIAN_ALBANIAN, // 1056F + UNKNOWN, // 10570..105FF + LINEAR_A, // 10600..10736 + UNKNOWN, // 10737..1073F + LINEAR_A, // 10740..10755 + UNKNOWN, // 10756..1075F + LINEAR_A, // 10760..10767 + UNKNOWN, // 10768..107FF + CYPRIOT, // 10800..10805 + UNKNOWN, // 10806..10807 + CYPRIOT, // 10808 + UNKNOWN, // 10809 + CYPRIOT, // 1080A..10835 + UNKNOWN, // 10836 + CYPRIOT, // 10837..10838 + UNKNOWN, // 10839..1083B + CYPRIOT, // 1083C + UNKNOWN, // 1083D..1083E + CYPRIOT, // 1083F + IMPERIAL_ARAMAIC, // 10840..10855 + UNKNOWN, // 10856 + IMPERIAL_ARAMAIC, // 10857..1085F + PALMYRENE, // 10860..1087F + NABATAEAN, // 10880..1089E + UNKNOWN, // 1089F..108A6 + NABATAEAN, // 108A7..108AF + UNKNOWN, // 108B0..108FF + PHOENICIAN, // 10900..1091B + UNKNOWN, // 1091C..1091E + PHOENICIAN, // 1091F + LYDIAN, // 10920..10939 + UNKNOWN, // 1093A..1093E + LYDIAN, // 1093F + UNKNOWN, // 10940..1097F + MEROITIC_HIEROGLYPHS, // 10980..1099F + MEROITIC_CURSIVE, // 109A0..109B7 + UNKNOWN, // 109B8..109BD + MEROITIC_CURSIVE, // 109BE..109BF + UNKNOWN, // 109C0..109FF + KHAROSHTHI, // 10A00..10A03 + UNKNOWN, // 10A04 + KHAROSHTHI, // 10A05..10A06 + UNKNOWN, // 10A07..10A0B + KHAROSHTHI, // 10A0C..10A13 + UNKNOWN, // 10A14 + KHAROSHTHI, // 10A15..10A17 + UNKNOWN, // 10A18 + KHAROSHTHI, // 10A19..10A33 + UNKNOWN, // 10A34..10A37 + KHAROSHTHI, // 10A38..10A3A + UNKNOWN, // 10A3B..10A3E + KHAROSHTHI, // 10A3F..10A47 + UNKNOWN, // 10A48..10A4F + KHAROSHTHI, // 10A50..10A58 + UNKNOWN, // 10A59..10A5F + OLD_SOUTH_ARABIAN, // 10A60..10A7F + OLD_NORTH_ARABIAN, // 10A80..10A9F + UNKNOWN, // 10AA0..10ABF + MANICHAEAN, // 10AC0..10AE6 + UNKNOWN, // 10AE7..10AEA + MANICHAEAN, // 10AEB..10AF6 + UNKNOWN, // 10AF7..10AFF + AVESTAN, // 10B00..10B35 + UNKNOWN, // 10B36..10B38 + AVESTAN, // 10B39..10B3F + INSCRIPTIONAL_PARTHIAN, // 10B40..10B55 + UNKNOWN, // 10B56..10B57 + INSCRIPTIONAL_PARTHIAN, // 10B58..10B5F + INSCRIPTIONAL_PAHLAVI, // 10B60..10B72 + UNKNOWN, // 10B73..10B77 + INSCRIPTIONAL_PAHLAVI, // 10B78..10B7F + PSALTER_PAHLAVI, // 10B80..10B91 + UNKNOWN, // 10B92..10B98 + PSALTER_PAHLAVI, // 10B99..10B9C + UNKNOWN, // 10B9D..10BA8 + PSALTER_PAHLAVI, // 10BA9..10BAF + UNKNOWN, // 10BB0..10BFF + OLD_TURKIC, // 10C00..10C48 + UNKNOWN, // 10C49..10E5F + ARABIC, // 10E60..10E7E + UNKNOWN, // 10E7F..10FFF + BRAHMI, // 11000..1104D + UNKNOWN, // 1104E..11051 + BRAHMI, // 11052..1106F + UNKNOWN, // 11070..1107E + BRAHMI, // 1107F + KAITHI, // 11080..110C1 + UNKNOWN, // 110C2..110CF + SORA_SOMPENG, // 110D0..110E8 + UNKNOWN, // 110E9..110EF + SORA_SOMPENG, // 110F0..110F9 + UNKNOWN, // 110FA..110FF + CHAKMA, // 11100..11134 + UNKNOWN, // 11135 + CHAKMA, // 11136..11143 + UNKNOWN, // 11144..1114F + MAHAJANI, // 11150..11176 + UNKNOWN, // 11177..1117F + SHARADA, // 11180..111C8 + UNKNOWN, // 111C9..111CC + SHARADA, // 111CD + UNKNOWN, // 111CE..111CF + SHARADA, // 111D0..111DA + UNKNOWN, // 111DB..111E0 + SINHALA, // 111E1..111F4 + UNKNOWN, // 111F5..111FF + KHOJKI, // 11200..11211 + UNKNOWN, // 11212 + KHOJKI, // 11213..1123D + UNKNOWN, // 1123E..112AF + KHUDAWADI, // 112B0..112EA + UNKNOWN, // 112EB..112EF + KHUDAWADI, // 112F0..112F9 + UNKNOWN, // 112FA..11300 + GRANTHA, // 11301..11303 + UNKNOWN, // 11304 + GRANTHA, // 11305..1130C + UNKNOWN, // 1130D..1130E + GRANTHA, // 1130F..11310 + UNKNOWN, // 11311..11312 + GRANTHA, // 11313..11328 + UNKNOWN, // 11329 + GRANTHA, // 1132A..11330 + UNKNOWN, // 11331 + GRANTHA, // 11332..11333 + UNKNOWN, // 11334 + GRANTHA, // 11335..11339 + UNKNOWN, // 1133A..1133B + GRANTHA, // 1133C..11344 + UNKNOWN, // 11345..11346 + GRANTHA, // 11347..11348 + UNKNOWN, // 11349..1134A + GRANTHA, // 1134B..1134D + UNKNOWN, // 1134E..11356 + GRANTHA, // 11357 + UNKNOWN, // 11358..1135C + GRANTHA, // 1135D..11363 + UNKNOWN, // 11364..11365 + GRANTHA, // 11366..1136C + UNKNOWN, // 1136D..1136F + GRANTHA, // 11370..11374 + UNKNOWN, // 11375..1147F + TIRHUTA, // 11480..114C7 + UNKNOWN, // 114C8..114CF + TIRHUTA, // 114D0..114D9 + UNKNOWN, // 114DA..1157F + SIDDHAM, // 11580..115B5 + UNKNOWN, // 115B6..115B7 + SIDDHAM, // 115B8..115C9 + UNKNOWN, // 115CA..115FF + MODI, // 11600..11644 + UNKNOWN, // 11645..1164F + MODI, // 11650..11659 + UNKNOWN, // 1165A..1167F + TAKRI, // 11680..116B7 + UNKNOWN, // 116B8..116BF + TAKRI, // 116C0..116C9 + UNKNOWN, // 116CA..1189F + WARANG_CITI, // 118A0..118F2 + UNKNOWN, // 118F3..118FE + WARANG_CITI, // 118FF + UNKNOWN, // 11900..11ABF + PAU_CIN_HAU, // 11AC0..11AF8 + UNKNOWN, // 11AF9..11FFF + CUNEIFORM, // 12000..12398 + UNKNOWN, // 12399..123FF + CUNEIFORM, // 12400..1246E + UNKNOWN, // 1246F + CUNEIFORM, // 12470..12474 + UNKNOWN, // 12475..12FFF + EGYPTIAN_HIEROGLYPHS, // 13000..1342E + UNKNOWN, // 1342F..167FF + BAMUM, // 16800..16A38 + UNKNOWN, // 16A39..16A3F + MRO, // 16A40..16A5E + UNKNOWN, // 16A5F + MRO, // 16A60..16A69 + UNKNOWN, // 16A6A..16A6D + MRO, // 16A6E..16A6F + UNKNOWN, // 16A70..16ACF + BASSA_VAH, // 16AD0..16AED + UNKNOWN, // 16AEE..16AEF + BASSA_VAH, // 16AF0..16AF5 + UNKNOWN, // 16AF6..16AFF + PAHAWH_HMONG, // 16B00..16B45 + UNKNOWN, // 16B46..16B4F + PAHAWH_HMONG, // 16B50..16B59 + UNKNOWN, // 16B5A + PAHAWH_HMONG, // 16B5B..16B61 + UNKNOWN, // 16B62 + PAHAWH_HMONG, // 16B63..16B77 + UNKNOWN, // 16B78..16B7C + PAHAWH_HMONG, // 16B7D..16B8F + UNKNOWN, // 16B90..16EFF + MIAO, // 16F00..16F44 + UNKNOWN, // 16F45..16F4F + MIAO, // 16F50..16F7E + UNKNOWN, // 16F7F..16F8E + MIAO, // 16F8F..16F9F + UNKNOWN, // 16FA0..1AFFF + KATAKANA, // 1B000 + HIRAGANA, // 1B001 + UNKNOWN, // 1B002..1BBFF + DUPLOYAN, // 1BC00..1BC6A + UNKNOWN, // 1BC6B..1BC6F + DUPLOYAN, // 1BC70..1BC7C + UNKNOWN, // 1BC7D..1BC7F + DUPLOYAN, // 1BC80..1BC88 + UNKNOWN, // 1BC89..1BC8F + DUPLOYAN, // 1BC90..1BC99 + UNKNOWN, // 1BC9A..1BC9B + DUPLOYAN, // 1BC9C..1BC9F + COMMON, // 1BCA0..1BCA3 + UNKNOWN, // 1BCA4..1CFFF + COMMON, // 1D000..1D0F5 + UNKNOWN, // 1D0F6..1D0FF + COMMON, // 1D100..1D126 + UNKNOWN, // 1D127..1D128 + COMMON, // 1D129..1D166 + INHERITED, // 1D167..1D169 + COMMON, // 1D16A..1D17A + INHERITED, // 1D17B..1D182 + COMMON, // 1D183..1D184 + INHERITED, // 1D185..1D18B + COMMON, // 1D18C..1D1A9 + INHERITED, // 1D1AA..1D1AD + COMMON, // 1D1AE..1D1DD + UNKNOWN, // 1D1DE..1D1FF + GREEK, // 1D200..1D245 + UNKNOWN, // 1D246..1D2FF + COMMON, // 1D300..1D356 + UNKNOWN, // 1D357..1D35F + COMMON, // 1D360..1D371 + UNKNOWN, // 1D372..1D3FF + COMMON, // 1D400..1D454 + UNKNOWN, // 1D455 + COMMON, // 1D456..1D49C + UNKNOWN, // 1D49D + COMMON, // 1D49E..1D49F + UNKNOWN, // 1D4A0..1D4A1 + COMMON, // 1D4A2 + UNKNOWN, // 1D4A3..1D4A4 + COMMON, // 1D4A5..1D4A6 + UNKNOWN, // 1D4A7..1D4A8 + COMMON, // 1D4A9..1D4AC + UNKNOWN, // 1D4AD + COMMON, // 1D4AE..1D4B9 + UNKNOWN, // 1D4BA + COMMON, // 1D4BB + UNKNOWN, // 1D4BC + COMMON, // 1D4BD..1D4C3 + UNKNOWN, // 1D4C4 + COMMON, // 1D4C5..1D505 + UNKNOWN, // 1D506 + COMMON, // 1D507..1D50A + UNKNOWN, // 1D50B..1D50C + COMMON, // 1D50D..1D514 + UNKNOWN, // 1D515 + COMMON, // 1D516..1D51C + UNKNOWN, // 1D51D + COMMON, // 1D51E..1D539 + UNKNOWN, // 1D53A + COMMON, // 1D53B..1D53E + UNKNOWN, // 1D53F + COMMON, // 1D540..1D544 + UNKNOWN, // 1D545 + COMMON, // 1D546 + UNKNOWN, // 1D547..1D549 + COMMON, // 1D54A..1D550 + UNKNOWN, // 1D551 + COMMON, // 1D552..1D6A5 + UNKNOWN, // 1D6A6..1D6A7 + COMMON, // 1D6A8..1D7CB + UNKNOWN, // 1D7CC..1D7CD + COMMON, // 1D7CE..1D7FF + UNKNOWN, // 1D800..1E7FF + MENDE_KIKAKUI, // 1E800..1E8C4 + UNKNOWN, // 1E8C5..1E8C6 + MENDE_KIKAKUI, // 1E8C7..1E8D6 + UNKNOWN, // 1E8D7..1EDFF + ARABIC, // 1EE00..1EE03 + UNKNOWN, // 1EE04 + ARABIC, // 1EE05..1EE1F + UNKNOWN, // 1EE20 + ARABIC, // 1EE21..1EE22 + UNKNOWN, // 1EE23 + ARABIC, // 1EE24 + UNKNOWN, // 1EE25..1EE26 + ARABIC, // 1EE27 + UNKNOWN, // 1EE28 + ARABIC, // 1EE29..1EE32 + UNKNOWN, // 1EE33 + ARABIC, // 1EE34..1EE37 + UNKNOWN, // 1EE38 + ARABIC, // 1EE39 + UNKNOWN, // 1EE3A + ARABIC, // 1EE3B + UNKNOWN, // 1EE3C..1EE41 + ARABIC, // 1EE42 + UNKNOWN, // 1EE43..1EE46 + ARABIC, // 1EE47 + UNKNOWN, // 1EE48 + ARABIC, // 1EE49 + UNKNOWN, // 1EE4A + ARABIC, // 1EE4B + UNKNOWN, // 1EE4C + ARABIC, // 1EE4D..1EE4F + UNKNOWN, // 1EE50 + ARABIC, // 1EE51..1EE52 + UNKNOWN, // 1EE53 + ARABIC, // 1EE54 + UNKNOWN, // 1EE55..1EE56 + ARABIC, // 1EE57 + UNKNOWN, // 1EE58 + ARABIC, // 1EE59 + UNKNOWN, // 1EE5A + ARABIC, // 1EE5B + UNKNOWN, // 1EE5C + ARABIC, // 1EE5D + UNKNOWN, // 1EE5E + ARABIC, // 1EE5F + UNKNOWN, // 1EE60 + ARABIC, // 1EE61..1EE62 + UNKNOWN, // 1EE63 + ARABIC, // 1EE64 + UNKNOWN, // 1EE65..1EE66 + ARABIC, // 1EE67..1EE6A + UNKNOWN, // 1EE6B + ARABIC, // 1EE6C..1EE72 + UNKNOWN, // 1EE73 + ARABIC, // 1EE74..1EE77 + UNKNOWN, // 1EE78 + ARABIC, // 1EE79..1EE7C + UNKNOWN, // 1EE7D + ARABIC, // 1EE7E + UNKNOWN, // 1EE7F + ARABIC, // 1EE80..1EE89 + UNKNOWN, // 1EE8A + ARABIC, // 1EE8B..1EE9B + UNKNOWN, // 1EE9C..1EEA0 + ARABIC, // 1EEA1..1EEA3 + UNKNOWN, // 1EEA4 + ARABIC, // 1EEA5..1EEA9 + UNKNOWN, // 1EEAA + ARABIC, // 1EEAB..1EEBB + UNKNOWN, // 1EEBC..1EEEF + ARABIC, // 1EEF0..1EEF1 + UNKNOWN, // 1EEF2..1EFFF + COMMON, // 1F000..1F02B + UNKNOWN, // 1F02C..1F02F + COMMON, // 1F030..1F093 + UNKNOWN, // 1F094..1F09F + COMMON, // 1F0A0..1F0AE + UNKNOWN, // 1F0AF..1F0B0 + COMMON, // 1F0B1..1F0BF + UNKNOWN, // 1F0C0 + COMMON, // 1F0C1..1F0CF + UNKNOWN, // 1F0D0 + COMMON, // 1F0D1..1F0F5 + UNKNOWN, // 1F0F6..1F0FF + COMMON, // 1F100..1F10C + UNKNOWN, // 1F10D..1F10F + COMMON, // 1F110..1F12E + UNKNOWN, // 1F12F + COMMON, // 1F130..1F16B + UNKNOWN, // 1F16C..1F16F + COMMON, // 1F170..1F19A + UNKNOWN, // 1F19B..1F1E5 + COMMON, // 1F1E6..1F1FF + HIRAGANA, // 1F200 + COMMON, // 1F201..1F202 + UNKNOWN, // 1F203..1F20F + COMMON, // 1F210..1F23A + UNKNOWN, // 1F23B..1F23F + COMMON, // 1F240..1F248 + UNKNOWN, // 1F249..1F24F + COMMON, // 1F250..1F251 + UNKNOWN, // 1F252..1F2FF + COMMON, // 1F300..1F32C + UNKNOWN, // 1F32D..1F32F + COMMON, // 1F330..1F37D + UNKNOWN, // 1F37E..1F37F + COMMON, // 1F380..1F3CE + UNKNOWN, // 1F3CF..1F3D3 + COMMON, // 1F3D4..1F3F7 + UNKNOWN, // 1F3F8..1F3FF + COMMON, // 1F400..1F4FE + UNKNOWN, // 1F4FF + COMMON, // 1F500..1F54A + UNKNOWN, // 1F54B..1F54F + COMMON, // 1F550..1F579 + UNKNOWN, // 1F57A + COMMON, // 1F57B..1F5A3 + UNKNOWN, // 1F5A4 + COMMON, // 1F5A5..1F642 + UNKNOWN, // 1F643..1F644 + COMMON, // 1F645..1F6CF + UNKNOWN, // 1F6D0..1F6DF + COMMON, // 1F6E0..1F6EC + UNKNOWN, // 1F6ED..1F6EF + COMMON, // 1F6F0..1F6F3 + UNKNOWN, // 1F6F4..1F6FF + COMMON, // 1F700..1F773 + UNKNOWN, // 1F774..1F77F + COMMON, // 1F780..1F7D4 + UNKNOWN, // 1F7D5..1F7FF + COMMON, // 1F800..1F80B + UNKNOWN, // 1F80C..1F80F + COMMON, // 1F810..1F847 + UNKNOWN, // 1F848..1F84F + COMMON, // 1F850..1F859 + UNKNOWN, // 1F85A..1F85F + COMMON, // 1F860..1F887 + UNKNOWN, // 1F888..1F88F + COMMON, // 1F890..1F8AD + UNKNOWN, // 1F8AE..1FFFF + HAN, // 20000..2A6D6 + UNKNOWN, // 2A6D7..2A6FF + HAN, // 2A700..2B734 + UNKNOWN, // 2B735..2B73F + HAN, // 2B740..2B81D + UNKNOWN, // 2B81E..2F7FF + HAN, // 2F800..2FA1D + UNKNOWN, // 2FA1E..E0000 + COMMON, // E0001 + UNKNOWN, // E0002..E001F + COMMON, // E0020..E007F + UNKNOWN, // E0080..E00FF + INHERITED, // E0100..E01EF + UNKNOWN // E01F0..10FFFF }; private static HashMap<String, Character.UnicodeScript> aliases; static { aliases = new HashMap<>(128); + aliases.put("AGHB", CAUCASIAN_ALBANIAN); aliases.put("ARAB", ARABIC); aliases.put("ARMI", IMPERIAL_ARAMAIC); aliases.put("ARMN", ARMENIAN); aliases.put("AVST", AVESTAN); aliases.put("BALI", BALINESE); aliases.put("BAMU", BAMUM); + aliases.put("BASS", BASSA_VAH); aliases.put("BATK", BATAK); aliases.put("BENG", BENGALI); aliases.put("BOPO", BOPOMOFO); - aliases.put("BRAI", BRAILLE); aliases.put("BRAH", BRAHMI); + aliases.put("BRAI", BRAILLE); aliases.put("BUGI", BUGINESE); aliases.put("BUHD", BUHID); aliases.put("CAKM", CHAKMA); @@ -4382,11 +7061,14 @@ class Character implements java.io.Serializable, Comparable<Character> { aliases.put("CYRL", CYRILLIC); aliases.put("DEVA", DEVANAGARI); aliases.put("DSRT", DESERET); + aliases.put("DUPL", DUPLOYAN); aliases.put("EGYP", EGYPTIAN_HIEROGLYPHS); + aliases.put("ELBA", ELBASAN); aliases.put("ETHI", ETHIOPIC); aliases.put("GEOR", GEORGIAN); aliases.put("GLAG", GLAGOLITIC); aliases.put("GOTH", GOTHIC); + aliases.put("GRAN", GRANTHA); aliases.put("GREK", GREEK); aliases.put("GUJR", GUJARATI); aliases.put("GURU", GURMUKHI); @@ -4395,6 +7077,7 @@ class Character implements java.io.Serializable, Comparable<Character> { aliases.put("HANO", HANUNOO); aliases.put("HEBR", HEBREW); aliases.put("HIRA", HIRAGANA); + aliases.put("HMNG", PAHAWH_HMONG); // it appears we don't have the KATAKANA_OR_HIRAGANA //aliases.put("HRKT", KATAKANA_OR_HIRAGANA); aliases.put("ITAL", OLD_ITALIC); @@ -4403,6 +7086,7 @@ class Character implements java.io.Serializable, Comparable<Character> { aliases.put("KANA", KATAKANA); aliases.put("KHAR", KHAROSHTHI); aliases.put("KHMR", KHMER); + aliases.put("KHOJ", KHOJKI); aliases.put("KNDA", KANNADA); aliases.put("KTHI", KAITHI); aliases.put("LANA", TAI_THAM); @@ -4410,27 +7094,39 @@ class Character implements java.io.Serializable, Comparable<Character> { aliases.put("LATN", LATIN); aliases.put("LEPC", LEPCHA); aliases.put("LIMB", LIMBU); + aliases.put("LINA", LINEAR_A); aliases.put("LINB", LINEAR_B); aliases.put("LISU", LISU); aliases.put("LYCI", LYCIAN); aliases.put("LYDI", LYDIAN); + aliases.put("MAHJ", MAHAJANI); aliases.put("MAND", MANDAIC); + aliases.put("MANI", MANICHAEAN); + aliases.put("MEND", MENDE_KIKAKUI); aliases.put("MERC", MEROITIC_CURSIVE); aliases.put("MERO", MEROITIC_HIEROGLYPHS); aliases.put("MLYM", MALAYALAM); + aliases.put("MODI", MODI); aliases.put("MONG", MONGOLIAN); + aliases.put("MROO", MRO); aliases.put("MTEI", MEETEI_MAYEK); aliases.put("MYMR", MYANMAR); + aliases.put("NARB", OLD_NORTH_ARABIAN); + aliases.put("NBAT", NABATAEAN); aliases.put("NKOO", NKO); aliases.put("OGAM", OGHAM); aliases.put("OLCK", OL_CHIKI); aliases.put("ORKH", OLD_TURKIC); aliases.put("ORYA", ORIYA); aliases.put("OSMA", OSMANYA); + aliases.put("PALM", PALMYRENE); + aliases.put("PAUC", PAU_CIN_HAU); + aliases.put("PERM", OLD_PERMIC); aliases.put("PHAG", PHAGS_PA); - aliases.put("PLRD", MIAO); aliases.put("PHLI", INSCRIPTIONAL_PAHLAVI); + aliases.put("PHLP", PSALTER_PAHLAVI); aliases.put("PHNX", PHOENICIAN); + aliases.put("PLRD", MIAO); aliases.put("PRTI", INSCRIPTIONAL_PARTHIAN); aliases.put("RJNG", REJANG); aliases.put("RUNR", RUNIC); @@ -4439,14 +7135,16 @@ class Character implements java.io.Serializable, Comparable<Character> { aliases.put("SAUR", SAURASHTRA); aliases.put("SHAW", SHAVIAN); aliases.put("SHRD", SHARADA); + aliases.put("SIDD", SIDDHAM); + aliases.put("SIND", KHUDAWADI); aliases.put("SINH", SINHALA); aliases.put("SORA", SORA_SOMPENG); aliases.put("SUND", SUNDANESE); aliases.put("SYLO", SYLOTI_NAGRI); aliases.put("SYRC", SYRIAC); aliases.put("TAGB", TAGBANWA); - aliases.put("TALE", TAI_LE); aliases.put("TAKR", TAKRI); + aliases.put("TALE", TAI_LE); aliases.put("TALU", NEW_TAI_LUE); aliases.put("TAML", TAMIL); aliases.put("TAVT", TAI_VIET); @@ -4456,8 +7154,10 @@ class Character implements java.io.Serializable, Comparable<Character> { aliases.put("THAA", THAANA); aliases.put("THAI", THAI); aliases.put("TIBT", TIBETAN); + aliases.put("TIRH", TIRHUTA); aliases.put("UGAR", UGARITIC); aliases.put("VAII", VAI); + aliases.put("WARA", WARANG_CITI); aliases.put("XPEO", OLD_PERSIAN); aliases.put("XSUX", CUNEIFORM); aliases.put("YIII", YI); @@ -6598,8 +9298,9 @@ class Character implements java.io.Serializable, Comparable<Character> { * * @param ch the character to be converted. * @return the numeric value of the character, as a nonnegative {@code int} - * value; -2 if the character has a numeric value that is not a - * nonnegative integer; -1 if the character has no numeric value. + * value; -2 if the character has a numeric value but the value + * can not be represented as a nonnegative {@code int} value; + * -1 if the character has no numeric value. * @see Character#forDigit(int, int) * @see Character#isDigit(char) * @since 1.1 @@ -6631,8 +9332,9 @@ class Character implements java.io.Serializable, Comparable<Character> { * * @param codePoint the character (Unicode code point) to be converted. * @return the numeric value of the character, as a nonnegative {@code int} - * value; -2 if the character has a numeric value that is not a - * nonnegative integer; -1 if the character has no numeric value. + * value; -2 if the character has a numeric value but the value + * can not be represented as a nonnegative {@code int} value; + * -1 if the character has no numeric value. * @see Character#forDigit(int, int) * @see Character#isDigit(int) * @since 1.5 @@ -7002,6 +9704,10 @@ class Character implements java.io.Serializable, Comparable<Character> { * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE * @see Character#DIRECTIONALITY_POP_DIRECTIONAL_FORMAT + * @see Character#DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE + * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE + * @see Character#DIRECTIONALITY_FIRST_STRONG_ISOLATE + * @see Character#DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE * @since 1.4 */ public static byte getDirectionality(char ch) { @@ -7039,6 +9745,10 @@ class Character implements java.io.Serializable, Comparable<Character> { * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE * @see Character#DIRECTIONALITY_POP_DIRECTIONAL_FORMAT DIRECTIONALITY_POP_DIRECTIONAL_FORMAT + * @see Character#DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE + * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE + * @see Character#DIRECTIONALITY_FIRST_STRONG_ISOLATE DIRECTIONALITY_FIRST_STRONG_ISOLATE + * @see Character#DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE * @since 1.5 */ public static byte getDirectionality(int codePoint) { diff --git a/jdk/src/java.base/share/classes/java/text/Bidi.java b/jdk/src/java.base/share/classes/java/text/Bidi.java index 3d0e1381adb..35a9b367eb6 100644 --- a/jdk/src/java.base/share/classes/java/text/Bidi.java +++ b/jdk/src/java.base/share/classes/java/text/Bidi.java @@ -185,7 +185,7 @@ public final class Bidi { AttributedString astr = new AttributedString(""); Bidi newBidi = new Bidi(astr.getIterator()); - return bidiBase.setLine(this, bidiBase, newBidi, newBidi.bidiBase,lineStart, lineLimit); + return bidiBase.setLine(this, bidiBase, newBidi, newBidi.bidiBase, lineStart, lineLimit); } /** diff --git a/jdk/src/java.base/share/classes/java/text/Normalizer.java b/jdk/src/java.base/share/classes/java/text/Normalizer.java index a97b4c1d9d9..82df51108cf 100644 --- a/jdk/src/java.base/share/classes/java/text/Normalizer.java +++ b/jdk/src/java.base/share/classes/java/text/Normalizer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,6 @@ package java.text; import sun.text.normalizer.NormalizerBase; -import sun.text.normalizer.NormalizerImpl; /** * This class provides the method <code>normalize</code> which transforms Unicode diff --git a/jdk/src/java.base/share/classes/sun/net/idn/StringPrep.java b/jdk/src/java.base/share/classes/sun/net/idn/StringPrep.java index 1d719ce35f7..433a386a3a4 100644 --- a/jdk/src/java.base/share/classes/sun/net/idn/StringPrep.java +++ b/jdk/src/java.base/share/classes/sun/net/idn/StringPrep.java @@ -50,7 +50,6 @@ import java.text.ParseException; import sun.text.Normalizer; import sun.text.normalizer.CharTrie; import sun.text.normalizer.Trie; -import sun.text.normalizer.NormalizerImpl; import sun.text.normalizer.VersionInfo; import sun.text.normalizer.UCharacter; import sun.text.normalizer.UCharacterIterator; @@ -227,7 +226,7 @@ public final class StringPrep { checkBiDi = ((indexes[OPTIONS] & CHECK_BIDI_ON) > 0); sprepUniVer = getVersionInfo(reader.getUnicodeVersion()); normCorrVer = getVersionInfo(indexes[NORM_CORRECTNS_LAST_UNI_VERSION]); - VersionInfo normUniVer = NormalizerImpl.getUnicodeVersion(); + VersionInfo normUniVer = UCharacter.getUnicodeVersion(); if(normUniVer.compareTo(sprepUniVer) < 0 && /* the Unicode version of SPREP file must be less than the Unicode Vesion of the normalization data */ normUniVer.compareTo(normCorrVer) < 0 && /* the Unicode version of the NormalizationCorrections.txt file should be less than the Unicode Vesion of the normalization data */ ((indexes[OPTIONS] & NORMALIZATION_ON) > 0) /* normalization turned on*/ @@ -354,7 +353,7 @@ public final class StringPrep { Normalizer.normalize( src.toString(), java.text.Normalizer.Form.NFKC, - Normalizer.UNICODE_3_2|NormalizerImpl.BEFORE_PRI_29)); + Normalizer.UNICODE_3_2)); } /* boolean isLabelSeparator(int ch){ diff --git a/jdk/src/java.base/share/classes/sun/text/ComposedCharIter.java b/jdk/src/java.base/share/classes/sun/text/ComposedCharIter.java index 53e0acb9cb1..da98dd60306 100644 --- a/jdk/src/java.base/share/classes/sun/text/ComposedCharIter.java +++ b/jdk/src/java.base/share/classes/sun/text/ComposedCharIter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * 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 @@ public final class ComposedCharIter { private static int decompNum; static { - int maxNum = 2000; //TBD: Unicode 4.0 only has 1926 canoDecomp... + int maxNum = 2100; chars = new int[maxNum]; decomps = new String[maxNum]; decompNum = NormalizerImpl.getDecompose(chars, decomps); diff --git a/jdk/src/java.base/share/classes/sun/text/Normalizer.java b/jdk/src/java.base/share/classes/sun/text/Normalizer.java index 82a6ebd9e40..f8f23abcdb4 100644 --- a/jdk/src/java.base/share/classes/sun/text/Normalizer.java +++ b/jdk/src/java.base/share/classes/sun/text/Normalizer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ package sun.text; import sun.text.normalizer.NormalizerBase; -import sun.text.normalizer.NormalizerImpl; +import sun.text.normalizer.UCharacter; /** * This Normalizer is for Unicode 3.2 support for IDNA only. @@ -93,6 +93,6 @@ public final class Normalizer { * @return combining class of the given character */ public static final int getCombiningClass(int ch) { - return NormalizerImpl.getCombiningClass(ch); + return UCharacter.getCombiningClass(ch); } } diff --git a/jdk/src/java.base/share/classes/sun/text/bidi/BidiBase.java b/jdk/src/java.base/share/classes/sun/text/bidi/BidiBase.java index 4691dbc853b..9ea7b98b000 100644 --- a/jdk/src/java.base/share/classes/sun/text/bidi/BidiBase.java +++ b/jdk/src/java.base/share/classes/sun/text/bidi/BidiBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * 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,17 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* - ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ +******************************************************************************* +* Copyright (C) 2001-2014, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ /* FOOD FOR THOUGHT: currently the reordering modes are a mixture of * algorithm for direct BiDi, algorithm for inverse Bidi and the bizarre @@ -52,12 +48,10 @@ package sun.text.bidi; -import java.io.IOException; import java.lang.reflect.Array; import java.text.AttributedCharacterIterator; import java.text.Bidi; import java.util.Arrays; -import java.util.MissingResourceException; import sun.misc.JavaAWTFontAccess; import sun.misc.SharedSecrets; import sun.text.normalizer.UBiDiProps; @@ -68,10 +62,9 @@ import sun.text.normalizer.UTF16; * * <h2>Bidi algorithm for ICU</h2> * - * This is an implementation of the Unicode Bidirectional algorithm. The + * This is an implementation of the Unicode Bidirectional Algorithm. The * algorithm is defined in the <a - * href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>, - * version 13, also described in The Unicode Standard, Version 4.0 . + * href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>. * <p> * * Note: Libraries that perform a bidirectional algorithm and reorder strings @@ -106,6 +99,7 @@ import sun.text.normalizer.UTF16; * <li>{@link #LTR} * <li>{@link #RTL} * <li>{@link #MIXED} + * <li>{@link #NEUTRAL} * </ul> * * <h3>Basic concept: levels</h3> @@ -167,6 +161,7 @@ import sun.text.normalizer.UTF16; * * <h3>Basic concept: Reordering Options</h3> * Reordering options can be applied during Bidi text transformations. + * * <p><b>See Also:</b> * <ul> * <li>{@link #setReorderingOptions} @@ -456,19 +451,134 @@ import sun.text.normalizer.UTF16; * }</pre> */ +/* + * General implementation notes: + * + * Throughout the implementation, there are comments like (W2) that refer to + * rules of the BiDi algorithm, in this example to the second rule of the + * resolution of weak types. + * + * For handling surrogate pairs, where two UChar's form one "abstract" (or UTF-32) + * character according to UTF-16, the second UChar gets the directional property of + * the entire character assigned, while the first one gets a BN, a boundary + * neutral, type, which is ignored by most of the algorithm according to + * rule (X9) and the implementation suggestions of the BiDi algorithm. + * + * Later, adjustWSLevels() will set the level for each BN to that of the + * following character (UChar), which results in surrogate pairs getting the + * same level on each of their surrogates. + * + * In a UTF-8 implementation, the same thing could be done: the last byte of + * a multi-byte sequence would get the "real" property, while all previous + * bytes of that sequence would get BN. + * + * It is not possible to assign all those parts of a character the same real + * property because this would fail in the resolution of weak types with rules + * that look at immediately surrounding types. + * + * As a related topic, this implementation does not remove Boundary Neutral + * types from the input, but ignores them wherever this is relevant. + * For example, the loop for the resolution of the weak types reads + * types until it finds a non-BN. + * Also, explicit embedding codes are neither changed into BN nor removed. + * They are only treated the same way real BNs are. + * As stated before, adjustWSLevels() takes care of them at the end. + * For the purpose of conformance, the levels of all these codes + * do not matter. + * + * Note that this implementation modifies the dirProps + * after the initial setup, when applying X5c (replace FSI by LRI or RLI), + * X6, N0 (replace paired brackets by L or R). + * + * In this implementation, the resolution of weak types (W1 to W6), + * neutrals (N1 and N2), and the assignment of the resolved level (In) + * are all done in one single loop, in resolveImplicitLevels(). + * Changes of dirProp values are done on the fly, without writing + * them back to the dirProps array. + * + * + * This implementation contains code that allows to bypass steps of the + * algorithm that are not needed on the specific paragraph + * in order to speed up the most common cases considerably, + * like text that is entirely LTR, or RTL text without numbers. + * + * Most of this is done by setting a bit for each directional property + * in a flags variable and later checking for whether there are + * any LTR characters or any RTL characters, or both, whether + * there are any explicit embedding codes, etc. + * + * If the (Xn) steps are performed, then the flags are re-evaluated, + * because they will then not contain the embedding codes any more + * and will be adjusted for override codes, so that subsequently + * more bypassing may be possible than what the initial flags suggested. + * + * If the text is not mixed-directional, then the + * algorithm steps for the weak type resolution are not performed, + * and all levels are set to the paragraph level. + * + * If there are no explicit embedding codes, then the (Xn) steps + * are not performed. + * + * If embedding levels are supplied as a parameter, then all + * explicit embedding codes are ignored, and the (Xn) steps + * are not performed. + * + * White Space types could get the level of the run they belong to, + * and are checked with a test of (flags&MASK_EMBEDDING) to + * consider if the paragraph direction should be considered in + * the flags variable. + * + * If there are no White Space types in the paragraph, then + * (L1) is not necessary in adjustWSLevels(). + */ + public class BidiBase { - class Point { + static class Point { int pos; /* position in text */ int flag; /* flag for LRM/RLM, before/after */ } - class InsertPoints { + static class InsertPoints { int size; int confirmed; Point[] points = new Point[0]; } + static class Opening { + int position; /* position of opening bracket */ + int match; /* matching char or -position of closing bracket */ + int contextPos; /* position of last strong char found before opening */ + short flags; /* bits for L or R/AL found within the pair */ + byte contextDir; /* L or R according to last strong char before opening */ + } + + static class IsoRun { + int contextPos; /* position of char determining context */ + short start; /* index of first opening entry for this run */ + short limit; /* index after last opening entry for this run */ + byte level; /* level of this run */ + byte lastStrong; /* bidi class of last strong char found in this run */ + byte lastBase; /* bidi class of last base char found in this run */ + byte contextDir; /* L or R to use as context for following openings */ + } + + static class BracketData { + Opening[] openings = new Opening[SIMPLE_PARAS_COUNT]; + int isoRunLast; /* index of last used entry */ + /* array of nested isolated sequence entries; can never excess UBIDI_MAX_EXPLICIT_LEVEL + + 1 for index 0, + 1 for before the first isolated sequence */ + IsoRun[] isoRuns = new IsoRun[MAX_EXPLICIT_LEVEL+2]; + boolean isNumbersSpecial; /*reordering mode for NUMBERS_SPECIAL */ + } + + static class Isolate { + int startON; + int start1; + short stateImp; + short state; + } + /** Paragraph level setting<p> * * Constant indicating that the base direction depends on the first strong @@ -482,7 +592,7 @@ public class BidiBase { * is assumed to be visual LTR, and the text after reordering is required * to be the corresponding logical string with appropriate contextual * direction. The direction of the result string will be RTL if either - * the righmost or leftmost strong character of the source text is RTL + * the rightmost or leftmost strong character of the source text is RTL * or Arabic Letter, the direction will be LTR otherwise.<p> * * If reordering option <code>OPTION_INSERT_MARKS</code> is set, an RLM may @@ -493,7 +603,7 @@ public class BidiBase { * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL * @stable ICU 3.8 */ - public static final byte INTERNAL_LEVEL_DEFAULT_LTR = (byte)0x7e; + public static final byte LEVEL_DEFAULT_LTR = (byte)0x7e; /** Paragraph level setting<p> * @@ -508,7 +618,7 @@ public class BidiBase { * is assumed to be visual LTR, and the text after reordering is required * to be the corresponding logical string with appropriate contextual * direction. The direction of the result string will be RTL if either - * the righmost or leftmost strong character of the source text is RTL + * the rightmost or leftmost strong character of the source text is RTL * or Arabic Letter, or if the text contains no strong character; * the direction will be LTR otherwise.<p> * @@ -520,21 +630,21 @@ public class BidiBase { * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL * @stable ICU 3.8 */ - public static final byte INTERNAL_LEVEL_DEFAULT_RTL = (byte)0x7f; + public static final byte LEVEL_DEFAULT_RTL = (byte)0x7f; /** * Maximum explicit embedding level. * (The maximum resolved level can be up to <code>MAX_EXPLICIT_LEVEL+1</code>). * @stable ICU 3.8 */ - public static final byte MAX_EXPLICIT_LEVEL = 61; + public static final byte MAX_EXPLICIT_LEVEL = 125; /** * Bit flag for level input. * Overrides directional properties. * @stable ICU 3.8 */ - public static final byte INTERNAL_LEVEL_OVERRIDE = (byte)0x80; + public static final byte LEVEL_OVERRIDE = (byte)0x80; /** * Special value which can be returned by the mapping methods when a @@ -554,12 +664,52 @@ public class BidiBase { */ public static final int MAP_NOWHERE = -1; + /** + * Left-to-right text. + * <ul> + * <li>As return value for <code>getDirection()</code>, it means + * that the source string contains no right-to-left characters, or + * that the source string is empty and the paragraph level is even. + * <li>As return value for <code>getBaseDirection()</code>, it + * means that the first strong character of the source string has + * a left-to-right direction. + * </ul> + * @stable ICU 3.8 + */ + public static final byte LTR = 0; + + /** + * Right-to-left text. + * <ul> + * <li>As return value for <code>getDirection()</code>, it means + * that the source string contains no left-to-right characters, or + * that the source string is empty and the paragraph level is odd. + * <li>As return value for <code>getBaseDirection()</code>, it + * means that the first strong character of the source string has + * a right-to-left direction. + * </ul> + * @stable ICU 3.8 + */ + public static final byte RTL = 1; + /** * Mixed-directional text. + * <p>As return value for <code>getDirection()</code>, it means + * that the source string contains both left-to-right and + * right-to-left characters. * @stable ICU 3.8 */ public static final byte MIXED = 2; + /** + * option bit for writeReordered(): + * keep combining characters after their base characters in RTL runs + * + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short KEEP_BASE_COMBINING = 1; + /** * option bit for writeReordered(): * replace characters with the "mirrored" property in RTL runs @@ -570,6 +720,50 @@ public class BidiBase { */ public static final short DO_MIRRORING = 2; + /** + * option bit for writeReordered(): + * surround the run with LRMs if necessary; + * this is part of the approximate "inverse Bidi" algorithm + * + * <p>This option does not imply corresponding adjustment of the index + * mappings.</p> + * + * @see #setInverse + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short INSERT_LRM_FOR_NUMERIC = 4; + + /** + * option bit for writeReordered(): + * remove Bidi control characters + * (this does not affect INSERT_LRM_FOR_NUMERIC) + * + * <p>This option does not imply corresponding adjustment of the index + * mappings.</p> + * + * @see #writeReordered + * @see #INSERT_LRM_FOR_NUMERIC + * @stable ICU 3.8 + */ + public static final short REMOVE_BIDI_CONTROLS = 8; + + /** + * option bit for writeReordered(): + * write the output in reverse order + * + * <p>This has the same effect as calling <code>writeReordered()</code> + * first without this option, and then calling + * <code>writeReverse()</code> without mirroring. + * Doing this in the same step is faster and avoids a temporary buffer. + * An example for using this option is output to a character terminal that + * is designed for RTL scripts and stores text in reverse order.</p> + * + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short OUTPUT_REVERSE = 16; + /** Reordering mode: Regular Logical to Visual Bidi algorithm according to Unicode. * @see #setReorderingMode * @stable ICU 3.8 @@ -600,7 +794,7 @@ public class BidiBase { * @see #setReorderingMode * @stable ICU 3.8 */ - private static final short REORDER_RUNS_ONLY = 3; + static final short REORDER_RUNS_ONLY = 3; /** Reordering mode: Visual to Logical algorithm which handles numbers * like L (same algorithm as selected by <code>setInverse(true)</code>. @@ -608,21 +802,21 @@ public class BidiBase { * @see #setReorderingMode * @stable ICU 3.8 */ - private static final short REORDER_INVERSE_NUMBERS_AS_L = 4; + static final short REORDER_INVERSE_NUMBERS_AS_L = 4; /** Reordering mode: Visual to Logical algorithm equivalent to the regular * Logical to Visual algorithm. * @see #setReorderingMode * @stable ICU 3.8 */ - private static final short REORDER_INVERSE_LIKE_DIRECT = 5; + static final short REORDER_INVERSE_LIKE_DIRECT = 5; /** Reordering mode: Inverse Bidi (Visual to Logical) algorithm for the * <code>REORDER_NUMBERS_SPECIAL</code> Bidi algorithm. * @see #setReorderingMode * @stable ICU 3.8 */ - private static final short REORDER_INVERSE_FOR_NUMBERS_SPECIAL = 6; + static final short REORDER_INVERSE_FOR_NUMBERS_SPECIAL = 6; /* Reordering mode values must be ordered so that all the regular logical to * visual modes come first, and all inverse Bidi modes come last. @@ -682,7 +876,7 @@ public class BidiBase { * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL * @stable ICU 3.8 */ - private static final int OPTION_INSERT_MARKS = 1; + static final int OPTION_INSERT_MARKS = 1; /** * Option bit for <code>setReorderingOptions</code>: @@ -704,7 +898,7 @@ public class BidiBase { * @see #REMOVE_BIDI_CONTROLS * @stable ICU 3.8 */ - private static final int OPTION_REMOVE_CONTROLS = 2; + static final int OPTION_REMOVE_CONTROLS = 2; /** * Option bit for <code>setReorderingOptions</code>: @@ -741,8 +935,7 @@ public class BidiBase { * part of the text.</p> * * <p>When the <code>OPTION_STREAMING</code> option is used, it is - * recommended to call <code>orderParagraphsLTR()</code> with argument - * <code>orderParagraphsLTR</code> set to <code>true</code> before calling + * recommended to call <code>orderParagraphsLTR(true)</code> before calling * <code>setPara()</code> so that later paragraphs may be concatenated to * previous paragraphs on the right. * </p> @@ -750,7 +943,6 @@ public class BidiBase { * @see #setReorderingMode * @see #setReorderingOptions * @see #getProcessedLength - * @see #orderParagraphsLTR * @stable ICU 3.8 */ private static final int OPTION_STREAMING = 4; @@ -760,7 +952,7 @@ public class BidiBase { * is easier with the same names for the Bidi types in the code as there. * See UCharacterDirection */ - private static final byte L = 0; + /* private */ static final byte L = 0; private static final byte R = 1; private static final byte EN = 2; private static final byte ES = 3; @@ -779,8 +971,55 @@ public class BidiBase { private static final byte PDF = 16; private static final byte NSM = 17; private static final byte BN = 18; + private static final byte FSI = 19; + private static final byte LRI = 20; + private static final byte RLI = 21; + private static final byte PDI = 22; + private static final byte ENL = PDI + 1; /* EN after W7 */ + private static final byte ENR = ENL + 1; /* EN not subject to W7 */ - private static final int MASK_R_AL = (1 << R | 1 << AL); + // Number of directional types + private static final int CHAR_DIRECTION_COUNT = 23; + + /** + * Enumerated property Bidi_Paired_Bracket_Type (new in Unicode 6.3). + * Used in UAX #9: Unicode Bidirectional Algorithm + * (http://www.unicode.org/reports/tr9/) + * Returns UCharacter.BidiPairedBracketType values. + * @stable ICU 52 + */ + public static final int BIDI_PAIRED_BRACKET_TYPE = 0x1015; + + /** + * Bidi Paired Bracket Type constants. + * + * @see UProperty#BIDI_PAIRED_BRACKET_TYPE + * @stable ICU 52 + */ + public static interface BidiPairedBracketType { + /** + * Not a paired bracket. + * @stable ICU 52 + */ + public static final int NONE = 0; + /** + * Open paired bracket. + * @stable ICU 52 + */ + public static final int OPEN = 1; + /** + * Close paired bracket. + * @stable ICU 52 + */ + public static final int CLOSE = 2; + /** + * @stable ICU 52 + */ + public static final int COUNT = 3; + } + + /* number of paras entries allocated initially */ + static final int SIMPLE_PARAS_COUNT = 10; private static final char CR = '\r'; private static final char LF = '\n'; @@ -790,12 +1029,22 @@ public class BidiBase { static final int RLM_BEFORE = 4; static final int RLM_AFTER = 8; + /* flags for Opening.flags */ + static final byte FOUND_L = (byte)DirPropFlag(L); + static final byte FOUND_R = (byte)DirPropFlag(R); + + /* + * The following bit is used for the directional isolate status. + * Stack entries corresponding to isolate sequences are greater than ISOLATE. + */ + static final int ISOLATE = 0x0100; + /* * reference to parent paragraph object (reference to self if this object is * a paragraph object); set to null in a newly opened object; set to a * real value after a successful execution of setPara or setLine */ - BidiBase paraBidi; + BidiBase paraBidi; final UBiDiProps bdp; @@ -828,6 +1077,15 @@ public class BidiBase { byte[] dirProps; byte[] levels; + /* are we performing an approximation of the "inverse Bidi" algorithm? */ + boolean isInverse; + + /* are we using the basic algorithm or its variation? */ + int reorderingMode; + + /* bitmask for reordering options */ + int reorderingOptions; + /* must block separators receive level 0? */ boolean orderParagraphsLTR; @@ -855,14 +1113,10 @@ public class BidiBase { /* implicitly at the paraLevel (rule (L1)) - levels may not reflect that */ int trailingWSStart; - /* fields for paragraph handling */ - int paraCount; /* set in getDirProps() */ - int[] parasMemory = new int[1]; - int[] paras; /* limits of paragraphs, filled in - ResolveExplicitLevels() or CheckExplicitLevels() */ - - /* for single paragraph text, we only need a tiny array of paras (no allocation) */ - int[] simpleParas = {0}; + /* fields for paragraph handling, set in getDirProps() */ + int paraCount; + int[] paras_limit = new int[SIMPLE_PARAS_COUNT]; + byte[] paras_level = new byte[SIMPLE_PARAS_COUNT]; /* fields for line reordering */ int runCount; /* ==-1: runs not set up yet */ @@ -872,9 +1126,18 @@ public class BidiBase { /* for non-mixed text, we only need a tiny array of runs (no allocation) */ BidiRun[] simpleRuns = {new BidiRun()}; + /* fields for managing isolate sequences */ + Isolate[] isolates; + + /* maximum or current nesting depth of isolate sequences */ + /* Within resolveExplicitLevels() and checkExplicitLevels(), this is the maximal + nesting encountered. + Within resolveImplicitLevels(), this is the index of the current isolates + stack entry. */ + int isolateCount; + /* mapping of runs in logical order to visual order */ int[] logicalToVisualRunsMap; - /* flag to indicate that the map has been updated */ boolean isGoodLogicalToVisualRunsMap; @@ -894,23 +1157,8 @@ public class BidiBase { return (1 << dir); } - /* - * The following bit is ORed to the property of characters in paragraphs - * with contextual RTL direction when paraLevel is contextual. - */ - static final byte CONTEXT_RTL_SHIFT = 6; - static final byte CONTEXT_RTL = (byte)(1<<CONTEXT_RTL_SHIFT); // 0x40 - static byte NoContextRTL(byte dir) - { - return (byte)(dir & ~CONTEXT_RTL); - } - - /* - * The following is a variant of DirProp.DirPropFlag() which ignores the - * CONTEXT_RTL bit. - */ - static int DirPropFlagNC(byte dir) { - return (1<<(dir & ~CONTEXT_RTL)); + boolean testDirPropFlagAt(int flag, int index) { + return ((DirPropFlag(dirProps[index]) & flag) != 0); } static final int DirPropFlagMultiRuns = DirPropFlag((byte)31); @@ -923,40 +1171,38 @@ public class BidiBase { static final int DirPropFlagLR(byte level) { return DirPropFlagLR[level & 1]; } static final int DirPropFlagE(byte level) { return DirPropFlagE[level & 1]; } static final int DirPropFlagO(byte level) { return DirPropFlagO[level & 1]; } + static final byte DirFromStrong(byte strong) { return strong == L ? L : R; } + static final byte NoOverride(byte level) { return (byte)(level & ~LEVEL_OVERRIDE); } - /* - * are there any characters that are LTR? - */ + /* are there any characters that are LTR or RTL? */ static final int MASK_LTR = - DirPropFlag(L)|DirPropFlag(EN)|DirPropFlag(AN)|DirPropFlag(LRE)|DirPropFlag(LRO); + DirPropFlag(L)|DirPropFlag(EN)|DirPropFlag(ENL)|DirPropFlag(ENR)|DirPropFlag(AN)|DirPropFlag(LRE)|DirPropFlag(LRO)|DirPropFlag(LRI); + static final int MASK_RTL = DirPropFlag(R)|DirPropFlag(AL)|DirPropFlag(RLE)|DirPropFlag(RLO)|DirPropFlag(RLI); - /* - * are there any characters that are RTL? - */ - static final int MASK_RTL = DirPropFlag(R)|DirPropFlag(AL)|DirPropFlag(RLE)|DirPropFlag(RLO); + static final int MASK_R_AL = DirPropFlag(R)|DirPropFlag(AL); /* explicit embedding codes */ - private static final int MASK_LRX = DirPropFlag(LRE)|DirPropFlag(LRO); - private static final int MASK_RLX = DirPropFlag(RLE)|DirPropFlag(RLO); - private static final int MASK_EXPLICIT = MASK_LRX|MASK_RLX|DirPropFlag(PDF); + private static final int MASK_EXPLICIT = DirPropFlag(LRE)|DirPropFlag(LRO)|DirPropFlag(RLE)|DirPropFlag(RLO)|DirPropFlag(PDF); private static final int MASK_BN_EXPLICIT = DirPropFlag(BN)|MASK_EXPLICIT; + /* explicit isolate codes */ + private static final int MASK_ISO = DirPropFlag(LRI)|DirPropFlag(RLI)|DirPropFlag(FSI)|DirPropFlag(PDI); + /* paragraph and segment separators */ private static final int MASK_B_S = DirPropFlag(B)|DirPropFlag(S); /* all types that are counted as White Space or Neutral in some steps */ - static final int MASK_WS = MASK_B_S|DirPropFlag(WS)|MASK_BN_EXPLICIT; - private static final int MASK_N = DirPropFlag(ON)|MASK_WS; + static final int MASK_WS = MASK_B_S|DirPropFlag(WS)|MASK_BN_EXPLICIT|MASK_ISO; /* types that are neutrals or could becomes neutrals in (Wn) */ - private static final int MASK_POSSIBLE_N = DirPropFlag(CS)|DirPropFlag(ES)|DirPropFlag(ET)|MASK_N; + private static final int MASK_POSSIBLE_N = DirPropFlag(ON)|DirPropFlag(CS)|DirPropFlag(ES)|DirPropFlag(ET)|MASK_WS; /* * These types may be changed to "e", * the embedding type (L or R) of the run, * in the Bidi algorithm (N2) */ - static final int MASK_EMBEDDING = DirPropFlag(NSM)|MASK_POSSIBLE_N; + private static final int MASK_EMBEDDING = DirPropFlag(NSM)|MASK_POSSIBLE_N; /* * the dirProp's L and R are defined to 0 and 1 values in UCharacterDirection.java @@ -968,30 +1214,25 @@ public class BidiBase { private static boolean IsDefaultLevel(byte level) { - return ((level & INTERNAL_LEVEL_DEFAULT_LTR) == INTERNAL_LEVEL_DEFAULT_LTR); - } - - byte GetParaLevelAt(int index) - { - return (defaultParaLevel != 0) ? - (byte)(dirProps[index]>>CONTEXT_RTL_SHIFT) : paraLevel; + return ((level & LEVEL_DEFAULT_LTR) == LEVEL_DEFAULT_LTR); } static boolean IsBidiControlChar(int c) { /* check for range 0x200c to 0x200f (ZWNJ, ZWJ, LRM, RLM) or 0x202a to 0x202e (LRE, RLE, PDF, LRO, RLO) */ - return (((c & 0xfffffffc) == 0x200c) || ((c >= 0x202a) && (c <= 0x202e))); + return (((c & 0xfffffffc) == 0x200c) || ((c >= 0x202a) && (c <= 0x202e)) + || ((c >= 0x2066) && (c <= 0x2069))); } - public void verifyValidPara() + void verifyValidPara() { - if (this != this.paraBidi) { - throw new IllegalStateException(""); + if (!(this == this.paraBidi)) { + throw new IllegalStateException(); } } - public void verifyValidParaOrLine() + void verifyValidParaOrLine() { BidiBase para = this.paraBidi; /* verify Para */ @@ -1004,7 +1245,7 @@ public class BidiBase { } } - public void verifyRange(int index, int start, int limit) + void verifyRange(int index, int start, int limit) { if (index < start || index >= limit) { throw new IllegalArgumentException("Value " + index + @@ -1012,14 +1253,6 @@ public class BidiBase { } } - public void verifyIndex(int index, int start, int limit) - { - if (index < start || index >= limit) { - throw new ArrayIndexOutOfBoundsException("Index " + index + - " is out of range " + start + " to " + limit); - } - } - /** * Allocate a <code>Bidi</code> object with preallocated memory * for internal structures. @@ -1051,7 +1284,7 @@ public class BidiBase { * @stable ICU 3.8 */ public BidiBase(int maxLength, int maxRunCount) - { + { /* check the argument values */ if (maxLength < 0 || maxRunCount < 0) { throw new IllegalArgumentException(); @@ -1075,12 +1308,7 @@ public class BidiBase { direction = 0; */ /* get Bidi properties */ - try { - bdp = UBiDiProps.getSingleton(); - } - catch (IOException e) { - throw new MissingResourceException(e.getMessage(), "(BidiProps)", ""); - } + bdp = UBiDiProps.INSTANCE; /* allocate memory for arrays as requested */ if (maxLength > 0) { @@ -1180,18 +1408,68 @@ public class BidiBase { getLevelsMemory(true, len); } - private void getInitialParasMemory(int len) - { - Object array = getMemory("Paras", parasMemory, Integer.TYPE, true, len); - parasMemory = (int[]) array; - } - private void getInitialRunsMemory(int len) { getRunsMemory(true, len); } -/* perform (P2)..(P3) ------------------------------------------------------- */ + /** + * Is this <code>Bidi</code> object set to perform the inverse Bidi + * algorithm? + * <p>Note: calling this method after setting the reordering mode with + * <code>setReorderingMode</code> will return <code>true</code> if the + * reordering mode was set to + * <code>REORDER_INVERSE_NUMBERS_AS_L</code>, <code>false</code> + * for all other values.</p> + * + * @return <code>true</code> if the <code>Bidi</code> object is set to + * perform the inverse Bidi algorithm by handling numbers as L. + * + * @see #setInverse + * @see #setReorderingMode + * @see #REORDER_INVERSE_NUMBERS_AS_L + * @stable ICU 3.8 + */ + public boolean isInverse() { + return isInverse; + } + + /* perform (P2)..(P3) ------------------------------------------------------- */ + + /* + * Check that there are enough entries in the arrays paras_limit and paras_level + */ + private void checkParaCount() { + int[] saveLimits; + byte[] saveLevels; + int count = paraCount; + if (count <= paras_level.length) + return; + int oldLength = paras_level.length; + saveLimits = paras_limit; + saveLevels = paras_level; + try { + paras_limit = new int[count * 2]; + paras_level = new byte[count * 2]; + } catch (Exception e) { + throw new OutOfMemoryError("Failed to allocate memory for paras"); + } + System.arraycopy(saveLimits, 0, paras_limit, 0, oldLength); + System.arraycopy(saveLevels, 0, paras_level, 0, oldLength); + } + + /* + * Get the directional properties for the text, calculate the flags bit-set, and + * determine the paragraph level if necessary (in paras_level[i]). + * FSI initiators are also resolved and their dirProp replaced with LRI or RLI. + * When encountering an FSI, it is initially replaced with an LRI, which is the + * default. Only if a strong R or AL is found within its scope will the LRI be + * replaced by an RLI. + */ + static final int NOT_SEEKING_STRONG = 0; /* 0: not contextual paraLevel, not after FSI */ + static final int SEEKING_STRONG_FOR_PARA = 1; /* 1: looking for first strong char in para */ + static final int SEEKING_STRONG_FOR_FSI = 2; /* 2: looking for first strong after FSI */ + static final int LOOKING_FOR_PDI = 3; /* 3: found strong after FSI, looking for PDI */ private void getDirProps() { @@ -1199,32 +1477,44 @@ public class BidiBase { flags = 0; /* collect all directionalities in the text */ int uchar; byte dirProp; - byte paraDirDefault = 0; /* initialize to avoid compiler warnings */ + byte defaultParaLevel = 0; /* initialize to avoid compiler warnings */ boolean isDefaultLevel = IsDefaultLevel(paraLevel); /* for inverse Bidi, the default para level is set to RTL if there is a strong R or AL character at either end of the text */ + boolean isDefaultLevelInverse=isDefaultLevel && + (reorderingMode == REORDER_INVERSE_LIKE_DIRECT || + reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL); lastArabicPos = -1; - controlCount = 0; + int controlCount = 0; + boolean removeBidiControls = (reorderingOptions & OPTION_REMOVE_CONTROLS) != 0; - final int NOT_CONTEXTUAL = 0; /* 0: not contextual paraLevel */ - final int LOOKING_FOR_STRONG = 1; /* 1: looking for first strong char */ - final int FOUND_STRONG_CHAR = 2; /* 2: found first strong char */ + byte state; + byte lastStrong = ON; /* for default level & inverse Bidi */ + /* The following stacks are used to manage isolate sequences. Those + sequences may be nested, but obviously never more deeply than the + maximum explicit embedding level. + lastStack is the index of the last used entry in the stack. A value of -1 + means that there is no open isolate sequence. + lastStack is reset to -1 on paragraph boundaries. */ + /* The following stack contains the position of the initiator of + each open isolate sequence */ + int[] isolateStartStack= new int[MAX_EXPLICIT_LEVEL+1]; + /* The following stack contains the last known state before + encountering the initiator of an isolate sequence */ + byte[] previousStateStack = new byte[MAX_EXPLICIT_LEVEL+1]; + int stackLast=-1; - int state; - int paraStart = 0; /* index of first char in paragraph */ - byte paraDir; /* == CONTEXT_RTL within paragraphs - starting with strong R char */ - byte lastStrongDir=0; /* for default level & inverse Bidi */ - int lastStrongLTR=0; /* for STREAMING option */ + if ((reorderingOptions & OPTION_STREAMING) != 0) + length = 0; + defaultParaLevel = (byte)(paraLevel & 1); if (isDefaultLevel) { - paraDirDefault = ((paraLevel & 1) != 0) ? CONTEXT_RTL : 0; - paraDir = paraDirDefault; - lastStrongDir = paraDirDefault; - state = LOOKING_FOR_STRONG; + paras_level[0] = defaultParaLevel; + lastStrong = defaultParaLevel; + state = SEEKING_STRONG_FOR_PARA; } else { - state = NOT_CONTEXTUAL; - paraDir = 0; + paras_level[0] = paraLevel; + state = NOT_SEEKING_STRONG; } /* count paragraphs and determine the paragraph level (P2..P3) */ /* @@ -1236,90 +1526,509 @@ public class BidiBase { for (i = 0; i < originalLength; /* i is incremented in the loop */) { i0 = i; /* index of first code unit */ uchar = UTF16.charAt(text, 0, originalLength, i); - i += Character.charCount(uchar); + i += UTF16.getCharCount(uchar); i1 = i - 1; /* index of last code unit, gets the directional property */ - dirProp = (byte)bdp.getClass(uchar); - + dirProp = (byte)getCustomizedClass(uchar); flags |= DirPropFlag(dirProp); - dirProps[i1] = (byte)(dirProp | paraDir); + dirProps[i1] = dirProp; if (i1 > i0) { /* set previous code units' properties to BN */ flags |= DirPropFlag(BN); do { - dirProps[--i1] = (byte)(BN | paraDir); + dirProps[--i1] = BN; } while (i1 > i0); } - if (state == LOOKING_FOR_STRONG) { - if (dirProp == L) { - state = FOUND_STRONG_CHAR; - if (paraDir != 0) { - paraDir = 0; - for (i1 = paraStart; i1 < i; i1++) { - dirProps[i1] &= ~CONTEXT_RTL; - } - } - continue; - } - if (dirProp == R || dirProp == AL) { - state = FOUND_STRONG_CHAR; - if (paraDir == 0) { - paraDir = CONTEXT_RTL; - for (i1 = paraStart; i1 < i; i1++) { - dirProps[i1] |= CONTEXT_RTL; - } - } - continue; - } + if (removeBidiControls && IsBidiControlChar(uchar)) { + controlCount++; } if (dirProp == L) { - lastStrongDir = 0; - lastStrongLTR = i; /* i is index to next character */ - } - else if (dirProp == R) { - lastStrongDir = CONTEXT_RTL; - } - else if (dirProp == AL) { - lastStrongDir = CONTEXT_RTL; - lastArabicPos = i-1; - } - else if (dirProp == B) { - if (i < originalLength) { /* B not last char in text */ - if (!((uchar == (int)CR) && (text[i] == (int)LF))) { - paraCount++; + if (state == SEEKING_STRONG_FOR_PARA) { + paras_level[paraCount - 1] = 0; + state = NOT_SEEKING_STRONG; + } + else if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); } - if (isDefaultLevel) { - state=LOOKING_FOR_STRONG; - paraStart = i; /* i is index to next character */ - paraDir = paraDirDefault; - lastStrongDir = paraDirDefault; + state = LOOKING_FOR_PDI; + } + lastStrong = L; + continue; + } + if (dirProp == R || dirProp == AL) { + if (state == SEEKING_STRONG_FOR_PARA) { + paras_level[paraCount - 1] = 1; + state = NOT_SEEKING_STRONG; + } + else if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + dirProps[isolateStartStack[stackLast]] = RLI; + flags |= DirPropFlag(RLI); + } + state = LOOKING_FOR_PDI; + } + lastStrong = R; + if (dirProp == AL) + lastArabicPos = i - 1; + continue; + } + if (dirProp >= FSI && dirProp <= RLI) { /* FSI, LRI or RLI */ + stackLast++; + if (stackLast <= MAX_EXPLICIT_LEVEL) { + isolateStartStack[stackLast] = i - 1; + previousStateStack[stackLast] = state; + } + if (dirProp == FSI) { + dirProps[i-1] = LRI; /* default if no strong char */ + state = SEEKING_STRONG_FOR_FSI; + } + else + state = LOOKING_FOR_PDI; + continue; + } + if (dirProp == PDI) { + if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); } } + if (stackLast >= 0) { + if (stackLast <= MAX_EXPLICIT_LEVEL) + state = previousStateStack[stackLast]; + stackLast--; + } + continue; + } + if (dirProp == B) { + if (i < originalLength && uchar == CR && text[i] == LF) /* do nothing on the CR */ + continue; + paras_limit[paraCount - 1] = i; + if (isDefaultLevelInverse && lastStrong == R) + paras_level[paraCount - 1] = 1; + if ((reorderingOptions & OPTION_STREAMING) != 0) { + /* When streaming, we only process whole paragraphs + thus some updates are only done on paragraph boundaries */ + length = i; /* i is index to next character */ + this.controlCount = controlCount; + } + if (i < originalLength) { /* B not last char in text */ + paraCount++; + checkParaCount(); /* check that there is enough memory for a new para entry */ + if (isDefaultLevel) { + paras_level[paraCount - 1] = defaultParaLevel; + state = SEEKING_STRONG_FOR_PARA; + lastStrong = defaultParaLevel; + } else { + paras_level[paraCount - 1] = paraLevel; + state = NOT_SEEKING_STRONG; + } + stackLast = -1; + } + continue; } } - if (isDefaultLevel) { - paraLevel = GetParaLevelAt(0); + /* +Ignore still open isolate sequences with overflow */ + if (stackLast > MAX_EXPLICIT_LEVEL) { + stackLast = MAX_EXPLICIT_LEVEL; + state=SEEKING_STRONG_FOR_FSI; /* to be on the safe side */ } - - /* The following line does nothing new for contextual paraLevel, but is - needed for absolute paraLevel. */ - flags |= DirPropFlagLR(paraLevel); + /* Resolve direction of still unresolved open FSI sequences */ + while (stackLast >= 0) { + if (state == SEEKING_STRONG_FOR_FSI) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); + break; + } + state = previousStateStack[stackLast]; + stackLast--; + } + /* When streaming, ignore text after the last paragraph separator */ + if ((reorderingOptions & OPTION_STREAMING) != 0) { + if (length < originalLength) + paraCount--; + } else { + paras_limit[paraCount - 1] = originalLength; + this.controlCount = controlCount; + } + /* For inverse bidi, default para direction is RTL if there is + a strong R or AL at either end of the paragraph */ + if (isDefaultLevelInverse && lastStrong == R) { + paras_level[paraCount - 1] = 1; + } + if (isDefaultLevel) { + paraLevel = paras_level[0]; + } + /* The following is needed to resolve the text direction for default level + paragraphs containing no strong character */ + for (i = 0; i < paraCount; i++) + flags |= DirPropFlagLR(paras_level[i]); if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) { flags |= DirPropFlag(L); } } + /* determine the paragraph level at position index */ + byte GetParaLevelAt(int pindex) + { + if (defaultParaLevel == 0 || pindex < paras_limit[0]) + return paraLevel; + int i; + for (i = 1; i < paraCount; i++) + if (pindex < paras_limit[i]) + break; + if (i >= paraCount) + i = paraCount - 1; + return paras_level[i]; + } + + /* Functions for handling paired brackets ----------------------------------- */ + + /* In the isoRuns array, the first entry is used for text outside of any + isolate sequence. Higher entries are used for each more deeply nested + isolate sequence. isoRunLast is the index of the last used entry. The + openings array is used to note the data of opening brackets not yet + matched by a closing bracket, or matched but still susceptible to change + level. + Each isoRun entry contains the index of the first and + one-after-last openings entries for pending opening brackets it + contains. The next openings entry to use is the one-after-last of the + most deeply nested isoRun entry. + isoRun entries also contain their current embedding level and the last + encountered strong character, since these will be needed to resolve + the level of paired brackets. */ + + private void bracketInit(BracketData bd) { + bd.isoRunLast = 0; + bd.isoRuns[0] = new IsoRun(); + bd.isoRuns[0].start = 0; + bd.isoRuns[0].limit = 0; + bd.isoRuns[0].level = GetParaLevelAt(0); + bd.isoRuns[0].lastStrong = bd.isoRuns[0].lastBase = bd.isoRuns[0].contextDir = (byte)(GetParaLevelAt(0) & 1); + bd.isoRuns[0].contextPos = 0; + bd.openings = new Opening[SIMPLE_PARAS_COUNT]; + bd.isNumbersSpecial = reorderingMode == REORDER_NUMBERS_SPECIAL || + reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL; + } + + /* paragraph boundary */ + private void bracketProcessB(BracketData bd, byte level) { + bd.isoRunLast = 0; + bd.isoRuns[0].limit = 0; + bd.isoRuns[0].level = level; + bd.isoRuns[0].lastStrong = bd.isoRuns[0].lastBase = bd.isoRuns[0].contextDir = (byte)(level & 1); + bd.isoRuns[0].contextPos = 0; + } + + /* LRE, LRO, RLE, RLO, PDF */ + private void bracketProcessBoundary(BracketData bd, int lastCcPos, + byte contextLevel, byte embeddingLevel) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + if ((DirPropFlag(dirProps[lastCcPos]) & MASK_ISO) != 0) /* after an isolate */ + return; + if (NoOverride(embeddingLevel) > NoOverride(contextLevel)) /* not a PDF */ + contextLevel = embeddingLevel; + pLastIsoRun.limit = pLastIsoRun.start; + pLastIsoRun.level = embeddingLevel; + pLastIsoRun.lastStrong = pLastIsoRun.lastBase = pLastIsoRun.contextDir = (byte)(contextLevel & 1); + pLastIsoRun.contextPos = lastCcPos; + } + + /* LRI or RLI */ + private void bracketProcessLRI_RLI(BracketData bd, byte level) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + short lastLimit; + pLastIsoRun.lastBase = ON; + lastLimit = pLastIsoRun.limit; + bd.isoRunLast++; + pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + if (pLastIsoRun == null) + pLastIsoRun = bd.isoRuns[bd.isoRunLast] = new IsoRun(); + pLastIsoRun.start = pLastIsoRun.limit = lastLimit; + pLastIsoRun.level = level; + pLastIsoRun.lastStrong = pLastIsoRun.lastBase = pLastIsoRun.contextDir = (byte)(level & 1); + pLastIsoRun.contextPos = 0; + } + + /* PDI */ + private void bracketProcessPDI(BracketData bd) { + IsoRun pLastIsoRun; + bd.isoRunLast--; + pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + pLastIsoRun.lastBase = ON; + } + + /* newly found opening bracket: create an openings entry */ + private void bracketAddOpening(BracketData bd, char match, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening pOpening; + if (pLastIsoRun.limit >= bd.openings.length) { /* no available new entry */ + Opening[] saveOpenings = bd.openings; + int count; + try { + count = bd.openings.length; + bd.openings = new Opening[count * 2]; + } catch (Exception e) { + throw new OutOfMemoryError("Failed to allocate memory for openings"); + } + System.arraycopy(saveOpenings, 0, bd.openings, 0, count); + } + pOpening = bd.openings[pLastIsoRun.limit]; + if (pOpening == null) + pOpening = bd.openings[pLastIsoRun.limit]= new Opening(); + pOpening.position = position; + pOpening.match = match; + pOpening.contextDir = pLastIsoRun.contextDir; + pOpening.contextPos = pLastIsoRun.contextPos; + pOpening.flags = 0; + pLastIsoRun.limit++; + } + + /* change N0c1 to N0c2 when a preceding bracket is assigned the embedding level */ + private void fixN0c(BracketData bd, int openingIndex, int newPropPosition, byte newProp) { + /* This function calls itself recursively */ + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening qOpening; + int k, openingPosition, closingPosition; + for (k = openingIndex+1; k < pLastIsoRun.limit; k++) { + qOpening = bd.openings[k]; + if (qOpening.match >= 0) /* not an N0c match */ + continue; + if (newPropPosition < qOpening.contextPos) + break; + if (newPropPosition >= qOpening.position) + continue; + if (newProp == qOpening.contextDir) + break; + openingPosition = qOpening.position; + dirProps[openingPosition] = newProp; + closingPosition = -(qOpening.match); + dirProps[closingPosition] = newProp; + qOpening.match = 0; /* prevent further changes */ + fixN0c(bd, k, openingPosition, newProp); + fixN0c(bd, k, closingPosition, newProp); + } + } + + /* process closing bracket; return L or R if N0b or N0c, ON if N0d */ + private byte bracketProcessClosing(BracketData bd, int openIdx, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening pOpening, qOpening; + byte direction; + boolean stable; + byte newProp; + pOpening = bd.openings[openIdx]; + direction = (byte)(pLastIsoRun.level & 1); + stable = true; /* assume stable until proved otherwise */ + + /* The stable flag is set when brackets are paired and their + level is resolved and cannot be changed by what will be + found later in the source string. + An unstable match can occur only when applying N0c, where + the resolved level depends on the preceding context, and + this context may be affected by text occurring later. + Example: RTL paragraph containing: abc[(latin) HEBREW] + When the closing parenthesis is encountered, it appears + that N0c1 must be applied since 'abc' sets an opposite + direction context and both parentheses receive level 2. + However, when the closing square bracket is processed, + N0b applies because of 'HEBREW' being included within the + brackets, thus the square brackets are treated like R and + receive level 1. However, this changes the preceding + context of the opening parenthesis, and it now appears + that N0c2 must be applied to the parentheses rather than + N0c1. */ + + if ((direction == 0 && (pOpening.flags & FOUND_L) > 0) || + (direction == 1 && (pOpening.flags & FOUND_R) > 0)) { /* N0b */ + newProp = direction; + } + else if ((pOpening.flags & (FOUND_L | FOUND_R)) != 0) { /* N0c */ + /* it is stable if there is no preceding text or in + conditions too complicated and not worth checking */ + stable = (openIdx == pLastIsoRun.start); + if (direction != pOpening.contextDir) + newProp = pOpening.contextDir; /* N0c1 */ + else + newProp = direction; /* N0c2 */ + } else { + /* forget this and any brackets nested within this pair */ + pLastIsoRun.limit = (short)openIdx; + return ON; /* N0d */ + } + dirProps[pOpening.position] = newProp; + dirProps[position] = newProp; + /* Update nested N0c pairs that may be affected */ + fixN0c(bd, openIdx, pOpening.position, newProp); + if (stable) { + pLastIsoRun.limit = (short)openIdx; /* forget any brackets nested within this pair */ + /* remove lower located synonyms if any */ + while (pLastIsoRun.limit > pLastIsoRun.start && + bd.openings[pLastIsoRun.limit - 1].position == pOpening.position) + pLastIsoRun.limit--; + } else { + int k; + pOpening.match = -position; + /* neutralize lower located synonyms if any */ + k = openIdx - 1; + while (k >= pLastIsoRun.start && + bd.openings[k].position == pOpening.position) + bd.openings[k--].match = 0; + /* neutralize any unmatched opening between the current pair; + this will also neutralize higher located synonyms if any */ + for (k = openIdx + 1; k < pLastIsoRun.limit; k++) { + qOpening =bd.openings[k]; + if (qOpening.position >= position) + break; + if (qOpening.match > 0) + qOpening.match = 0; + } + } + return newProp; + } + + /* handle strong characters, digits and candidates for closing brackets */ + private void bracketProcessChar(BracketData bd, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + byte dirProp, newProp; + byte level; + dirProp = dirProps[position]; + if (dirProp == ON) { + char c, match; + int idx; + /* First see if it is a matching closing bracket. Hopefully, this is + more efficient than checking if it is a closing bracket at all */ + c = text[position]; + for (idx = pLastIsoRun.limit - 1; idx >= pLastIsoRun.start; idx--) { + if (bd.openings[idx].match != c) + continue; + /* We have a match */ + newProp = bracketProcessClosing(bd, idx, position); + if(newProp == ON) { /* N0d */ + c = 0; /* prevent handling as an opening */ + break; + } + pLastIsoRun.lastBase = ON; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + level = levels[position]; + if ((level & LEVEL_OVERRIDE) != 0) { /* X4, X5 */ + short flag; + int i; + newProp = (byte)(level & 1); + pLastIsoRun.lastStrong = newProp; + flag = (short)DirPropFlag(newProp); + for (i = pLastIsoRun.start; i < idx; i++) + bd.openings[i].flags |= flag; + /* matching brackets are not overridden by LRO/RLO */ + levels[position] &= ~LEVEL_OVERRIDE; + } + /* matching brackets are not overridden by LRO/RLO */ + levels[bd.openings[idx].position] &= ~LEVEL_OVERRIDE; + return; + } + /* We get here only if the ON character is not a matching closing + bracket or it is a case of N0d */ + /* Now see if it is an opening bracket */ + if (c != 0) { + match = (char)UCharacter.getBidiPairedBracket(c); /* get the matching char */ + } else { + match = 0; + } + if (match != c && /* has a matching char */ + UCharacter.getIntPropertyValue(c, BIDI_PAIRED_BRACKET_TYPE) == + /* opening bracket */ BidiPairedBracketType.OPEN) { + /* special case: process synonyms + create an opening entry for each synonym */ + if (match == 0x232A) { /* RIGHT-POINTING ANGLE BRACKET */ + bracketAddOpening(bd, (char)0x3009, position); + } + else if (match == 0x3009) { /* RIGHT ANGLE BRACKET */ + bracketAddOpening(bd, (char)0x232A, position); + } + bracketAddOpening(bd, match, position); + } + } + level = levels[position]; + if ((level & LEVEL_OVERRIDE) != 0) { /* X4, X5 */ + newProp = (byte)(level & 1); + if (dirProp != S && dirProp != WS && dirProp != ON) + dirProps[position] = newProp; + pLastIsoRun.lastBase = newProp; + pLastIsoRun.lastStrong = newProp; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + } + else if (dirProp <= R || dirProp == AL) { + newProp = DirFromStrong(dirProp); + pLastIsoRun.lastBase = dirProp; + pLastIsoRun.lastStrong = dirProp; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + } + else if(dirProp == EN) { + pLastIsoRun.lastBase = EN; + if (pLastIsoRun.lastStrong == L) { + newProp = L; /* W7 */ + if (!bd.isNumbersSpecial) + dirProps[position] = ENL; + pLastIsoRun.contextDir = L; + pLastIsoRun.contextPos = position; + } + else { + newProp = R; /* N0 */ + if (pLastIsoRun.lastStrong == AL) + dirProps[position] = AN; /* W2 */ + else + dirProps[position] = ENR; + pLastIsoRun.contextDir = R; + pLastIsoRun.contextPos = position; + } + } + else if (dirProp == AN) { + newProp = R; /* N0 */ + pLastIsoRun.lastBase = AN; + pLastIsoRun.contextDir = R; + pLastIsoRun.contextPos = position; + } + else if (dirProp == NSM) { + /* if the last real char was ON, change NSM to ON so that it + will stay ON even if the last real char is a bracket which + may be changed to L or R */ + newProp = pLastIsoRun.lastBase; + if (newProp == ON) + dirProps[position] = newProp; + } + else { + newProp = dirProp; + pLastIsoRun.lastBase = dirProp; + } + if (newProp <= R || newProp == AL) { + int i; + short flag = (short)DirPropFlag(DirFromStrong(newProp)); + for (i = pLastIsoRun.start; i < pLastIsoRun.limit; i++) + if (position > bd.openings[i].position) + bd.openings[i].flags |= flag; + } + } + /* perform (X1)..(X9) ------------------------------------------------------- */ /* determine if the text is mixed-directional or single-directional */ private byte directionFromFlags() { + /* if the text contains AN and neutrals, then some neutrals may become RTL */ if (!((flags & MASK_RTL) != 0 || ((flags & DirPropFlag(AN)) != 0 && (flags & MASK_POSSIBLE_N) != 0))) { - return Bidi.DIRECTION_LEFT_TO_RIGHT; + return LTR; } else if ((flags & MASK_LTR) == 0) { - return Bidi.DIRECTION_RIGHT_TO_LEFT; + return RTL; } else { return MIXED; } @@ -1330,16 +2039,16 @@ public class BidiBase { * Recalculate the flags to have them reflect the real properties * after taking the explicit embeddings into account. * - * The Bidi algorithm is designed to result in the same behavior whether embedding + * The BiDi algorithm is designed to result in the same behavior whether embedding * levels are externally specified (from "styled text", supposedly the preferred - * method) or set by explicit embedding codes (LRx, RLx, PDF) in the plain text. - * That is why (X9) instructs to remove all explicit codes (and BN). - * However, in a real implementation, this removal of these codes and their index + * method) or set by explicit embedding codes (LRx, RLx, PDF, FSI, PDI) in the plain text. + * That is why (X9) instructs to remove all not-isolate explicit codes (and BN). + * However, in a real implementation, the removal of these codes and their index * positions in the plain text is undesirable since it would result in * reallocated, reindexed text. * Instead, this implementation leaves the codes in there and just ignores them * in the subsequent processing. - * In order to get the same reordering behavior, positions with a BN or an + * In order to get the same reordering behavior, positions with a BN or a not-isolate * explicit embedding code just get the same level assigned as the last "real" * character. * @@ -1351,185 +2060,281 @@ public class BidiBase { * This limits the scope of the implicit rules in effectively * the same way as the run limits. * - * Instead, this implementation does not modify these codes. + * Instead, this implementation does not modify these codes, except for + * paired brackets whose properties (ON) may be replaced by L or R. * On one hand, the paragraph has to be scanned for same-level-runs, but * on the other hand, this saves another loop to reset these codes, * or saves making and modifying a copy of dirProps[]. * * - * Note that (Pn) and (Xn) changed significantly from version 4 of the Bidi algorithm. + * Note that (Pn) and (Xn) changed significantly from version 4 of the BiDi algorithm. * * * Handling the stack of explicit levels (Xn): * - * With the Bidi stack of explicit levels, - * as pushed with each LRE, RLE, LRO, and RLO and popped with each PDF, - * the explicit level must never exceed MAX_EXPLICIT_LEVEL==61. + * With the BiDi stack of explicit levels, as pushed with each + * LRE, RLE, LRO, RLO, LRI, RLI and FSI and popped with each PDF and PDI, + * the explicit level must never exceed MAX_EXPLICIT_LEVEL. * * In order to have a correct push-pop semantics even in the case of overflows, - * there are two overflow counters: - * - countOver60 is incremented with each LRx at level 60 - * - from level 60, one RLx increases the level to 61 - * - countOver61 is incremented with each LRx and RLx at level 61 - * - * Popping levels with PDF must work in the opposite order so that level 61 - * is correct at the correct point. Underflows (too many PDFs) must be checked. + * overflow counters and a valid isolate counter are used as described in UAX#9 + * section 3.3.2 "Explicit Levels and Directions". * * This implementation assumes that MAX_EXPLICIT_LEVEL is odd. + * + * Returns the direction + * */ private byte resolveExplicitLevels() { int i = 0; byte dirProp; byte level = GetParaLevelAt(0); - byte dirct; - int paraIndex = 0; + isolateCount = 0; /* determine if the text is mixed-directional or single-directional */ dirct = directionFromFlags(); - /* we may not need to resolve any explicit levels, but for multiple - paragraphs we want to loop on all chars to set the para boundaries */ - if ((dirct != MIXED) && (paraCount == 1)) { + /* we may not need to resolve any explicit levels */ + if (dirct != MIXED) { /* not mixed directionality: levels don't matter - trailingWSStart will be 0 */ - } else if ((paraCount == 1) && - ((flags & MASK_EXPLICIT) == 0)) { - /* mixed, but all characters are at the same embedding level */ - /* or we are in "inverse Bidi" */ - /* and we don't have contextual multiple paragraphs with some B char */ + return dirct; + } + + if (reorderingMode > REORDER_LAST_LOGICAL_TO_VISUAL) { + /* inverse BiDi: mixed, but all characters are at the same embedding level */ /* set all levels to the paragraph level */ - for (i = 0; i < length; ++i) { - levels[i] = level; + int paraIndex, start, limit; + for (paraIndex = 0; paraIndex < paraCount; paraIndex++) { + if (paraIndex == 0) + start = 0; + else + start = paras_limit[paraIndex - 1]; + limit = paras_limit[paraIndex]; + level = paras_level[paraIndex]; + for (i = start; i < limit; i++) + levels[i] =level; } - } else { - /* continue to perform (Xn) */ - - /* (X1) level is set for all codes, embeddingLevel keeps track of the push/pop operations */ - /* both variables may carry the LEVEL_OVERRIDE flag to indicate the override status */ - byte embeddingLevel = level; - byte newLevel; - byte stackTop = 0; - - byte[] stack = new byte[MAX_EXPLICIT_LEVEL]; /* we never push anything >=MAX_EXPLICIT_LEVEL */ - int countOver60 = 0; - int countOver61 = 0; /* count overflows of explicit levels */ - - /* recalculate the flags */ - flags = 0; - - for (i = 0; i < length; ++i) { - dirProp = NoContextRTL(dirProps[i]); - switch(dirProp) { - case LRE: - case LRO: - /* (X3, X5) */ - newLevel = (byte)((embeddingLevel+2) & ~(INTERNAL_LEVEL_OVERRIDE | 1)); /* least greater even level */ - if (newLevel <= MAX_EXPLICIT_LEVEL) { - stack[stackTop] = embeddingLevel; - ++stackTop; - embeddingLevel = newLevel; - if (dirProp == LRO) { - embeddingLevel |= INTERNAL_LEVEL_OVERRIDE; + return dirct; /* no bracket matching for inverse BiDi */ + } + if ((flags & (MASK_EXPLICIT | MASK_ISO)) == 0) { + /* no embeddings, set all levels to the paragraph level */ + /* we still have to perform bracket matching */ + int paraIndex, start, limit; + BracketData bracketData = new BracketData(); + bracketInit(bracketData); + for (paraIndex = 0; paraIndex < paraCount; paraIndex++) { + if (paraIndex == 0) + start = 0; + else + start = paras_limit[paraIndex-1]; + limit = paras_limit[paraIndex]; + level = paras_level[paraIndex]; + for (i = start; i < limit; i++) { + levels[i] = level; + dirProp = dirProps[i]; + if (dirProp == BN) + continue; + if (dirProp == B) { + if ((i + 1) < length) { + if (text[i] == CR && text[i + 1] == LF) + continue; /* skip CR when followed by LF */ + bracketProcessB(bracketData, level); } - /* we don't need to set LEVEL_OVERRIDE off for LRE - since this has already been done for newLevel which is - the source for embeddingLevel. - */ - } else if ((embeddingLevel & ~INTERNAL_LEVEL_OVERRIDE) == MAX_EXPLICIT_LEVEL) { - ++countOver61; - } else /* (embeddingLevel & ~INTERNAL_LEVEL_OVERRIDE) == MAX_EXPLICIT_LEVEL-1 */ { - ++countOver60; - } - flags |= DirPropFlag(BN); - break; - case RLE: - case RLO: - /* (X2, X4) */ - newLevel=(byte)(((embeddingLevel & ~INTERNAL_LEVEL_OVERRIDE) + 1) | 1); /* least greater odd level */ - if (newLevel<=MAX_EXPLICIT_LEVEL) { - stack[stackTop] = embeddingLevel; - ++stackTop; - embeddingLevel = newLevel; - if (dirProp == RLO) { - embeddingLevel |= INTERNAL_LEVEL_OVERRIDE; - } - /* we don't need to set LEVEL_OVERRIDE off for RLE - since this has already been done for newLevel which is - the source for embeddingLevel. - */ - } else { - ++countOver61; - } - flags |= DirPropFlag(BN); - break; - case PDF: - /* (X7) */ - /* handle all the overflow cases first */ - if (countOver61 > 0) { - --countOver61; - } else if (countOver60 > 0 && (embeddingLevel & ~INTERNAL_LEVEL_OVERRIDE) != MAX_EXPLICIT_LEVEL) { - /* handle LRx overflows from level 60 */ - --countOver60; - } else if (stackTop > 0) { - /* this is the pop operation; it also pops level 61 while countOver60>0 */ - --stackTop; - embeddingLevel = stack[stackTop]; - /* } else { (underflow) */ - } - flags |= DirPropFlag(BN); - break; - case B: - stackTop = 0; - countOver60 = 0; - countOver61 = 0; - level = GetParaLevelAt(i); - if ((i + 1) < length) { - embeddingLevel = GetParaLevelAt(i+1); - if (!((text[i] == CR) && (text[i + 1] == LF))) { - paras[paraIndex++] = i+1; - } - } - flags |= DirPropFlag(B); - break; - case BN: - /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */ - /* they will get their levels set correctly in adjustWSLevels() */ - flags |= DirPropFlag(BN); - break; - default: - /* all other types get the "real" level */ - if (level != embeddingLevel) { - level = embeddingLevel; - if ((level & INTERNAL_LEVEL_OVERRIDE) != 0) { - flags |= DirPropFlagO(level) | DirPropFlagMultiRuns; - } else { - flags |= DirPropFlagE(level) | DirPropFlagMultiRuns; - } - } - if ((level & INTERNAL_LEVEL_OVERRIDE) == 0) { - flags |= DirPropFlag(dirProp); + continue; } + bracketProcessChar(bracketData, i); + } + } + return dirct; + } + /* continue to perform (Xn) */ + + /* (X1) level is set for all codes, embeddingLevel keeps track of the push/pop operations */ + /* both variables may carry the LEVEL_OVERRIDE flag to indicate the override status */ + byte embeddingLevel = level, newLevel; + byte previousLevel = level; /* previous level for regular (not CC) characters */ + int lastCcPos = 0; /* index of last effective LRx,RLx, PDx */ + + /* The following stack remembers the embedding level and the ISOLATE flag of level runs. + stackLast points to its current entry. */ + short[] stack = new short[MAX_EXPLICIT_LEVEL + 2]; /* we never push anything >= MAX_EXPLICIT_LEVEL + but we need one more entry as base */ + int stackLast = 0; + int overflowIsolateCount = 0; + int overflowEmbeddingCount = 0; + int validIsolateCount = 0; + BracketData bracketData = new BracketData(); + bracketInit(bracketData); + stack[0] = level; /* initialize base entry to para level, no override, no isolate */ + + /* recalculate the flags */ + flags = 0; + + for (i = 0; i < length; i++) { + dirProp = dirProps[i]; + switch (dirProp) { + case LRE: + case RLE: + case LRO: + case RLO: + /* (X2, X3, X4, X5) */ + flags |= DirPropFlag(BN); + levels[i] = previousLevel; + if (dirProp == LRE || dirProp == LRO) { + /* least greater even level */ + newLevel = (byte)((embeddingLevel+2) & ~(LEVEL_OVERRIDE | 1)); + } else { + /* least greater odd level */ + newLevel = (byte)((NoOverride(embeddingLevel) + 1) | 1); + } + if (newLevel <= MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0 && + overflowEmbeddingCount == 0) { + lastCcPos = i; + embeddingLevel = newLevel; + if (dirProp == LRO || dirProp == RLO) + embeddingLevel |= LEVEL_OVERRIDE; + stackLast++; + stack[stackLast] = embeddingLevel; + /* we don't need to set LEVEL_OVERRIDE off for LRE and RLE + since this has already been done for newLevel which is + the source for embeddingLevel. + */ + } else { + if (overflowIsolateCount == 0) + overflowEmbeddingCount++; + } + break; + case PDF: + /* (X7) */ + flags |= DirPropFlag(BN); + levels[i] = previousLevel; + /* handle all the overflow cases first */ + if (overflowIsolateCount > 0) { break; } - - /* - * We need to set reasonable levels even on BN codes and - * explicit codes because we will later look at same-level runs (X10). - */ - levels[i] = level; + if (overflowEmbeddingCount > 0) { + overflowEmbeddingCount--; + break; + } + if (stackLast > 0 && stack[stackLast] < ISOLATE) { /* not an isolate entry */ + lastCcPos = i; + stackLast--; + embeddingLevel = (byte)stack[stackLast]; + } + break; + case LRI: + case RLI: + flags |= DirPropFlag(ON) | DirPropFlagLR(embeddingLevel); + levels[i] = NoOverride(embeddingLevel); + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, + previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + } + previousLevel = embeddingLevel; + /* (X5a, X5b) */ + if (dirProp == LRI) + /* least greater even level */ + newLevel=(byte)((embeddingLevel+2)&~(LEVEL_OVERRIDE|1)); + else + /* least greater odd level */ + newLevel=(byte)((NoOverride(embeddingLevel)+1)|1); + if (newLevel <= MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0 + && overflowEmbeddingCount == 0) { + flags |= DirPropFlag(dirProp); + lastCcPos = i; + validIsolateCount++; + if (validIsolateCount > isolateCount) + isolateCount = validIsolateCount; + embeddingLevel = newLevel; + /* we can increment stackLast without checking because newLevel + will exceed UBIDI_MAX_EXPLICIT_LEVEL before stackLast overflows */ + stackLast++; + stack[stackLast] = (short)(embeddingLevel + ISOLATE); + bracketProcessLRI_RLI(bracketData, embeddingLevel); + } else { + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + overflowIsolateCount++; + } + break; + case PDI: + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, + previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + } + /* (X6a) */ + if (overflowIsolateCount > 0) { + overflowIsolateCount--; + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + } + else if (validIsolateCount > 0) { + flags |= DirPropFlag(PDI); + lastCcPos = i; + overflowEmbeddingCount = 0; + while (stack[stackLast] < ISOLATE) /* pop embedding entries */ + stackLast--; /* until the last isolate entry */ + stackLast--; /* pop also the last isolate entry */ + validIsolateCount--; + bracketProcessPDI(bracketData); + } else + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + embeddingLevel = (byte)(stack[stackLast] & ~ISOLATE); + flags |= DirPropFlag(ON) | DirPropFlagLR(embeddingLevel); + previousLevel = embeddingLevel; + levels[i] = NoOverride(embeddingLevel); + break; + case B: + flags |= DirPropFlag(B); + levels[i] = GetParaLevelAt(i); + if ((i + 1) < length) { + if (text[i] == CR && text[i + 1] == LF) + break; /* skip CR when followed by LF */ + overflowEmbeddingCount = overflowIsolateCount = 0; + validIsolateCount = 0; + stackLast = 0; + previousLevel = embeddingLevel = GetParaLevelAt(i + 1); + stack[0] = embeddingLevel; /* initialize base entry to para level, no override, no isolate */ + bracketProcessB(bracketData, embeddingLevel); + } + break; + case BN: + /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */ + /* they will get their levels set correctly in adjustWSLevels() */ + levels[i] = previousLevel; + flags |= DirPropFlag(BN); + break; + default: + /* all other types are normal characters and get the "real" level */ + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, + previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + if ((embeddingLevel & LEVEL_OVERRIDE) != 0) + flags |= DirPropFlagO(embeddingLevel); + else + flags |= DirPropFlagE(embeddingLevel); + } + previousLevel = embeddingLevel; + levels[i] = embeddingLevel; + bracketProcessChar(bracketData, i); + /* the dirProp may have been changed in bracketProcessChar() */ + flags |= DirPropFlag(dirProps[i]); + break; } - if ((flags & MASK_EMBEDDING) != 0) { - flags |= DirPropFlagLR(paraLevel); - } - if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) { - flags |= DirPropFlag(L); - } - - /* subsequently, ignore the explicit codes and BN (X9) */ - - /* again, determine if the text is mixed-directional or single-directional */ - dirct = directionFromFlags(); } + if ((flags & MASK_EMBEDDING) != 0) { + flags |= DirPropFlagLR(paraLevel); + } + if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) { + flags |= DirPropFlag(L); + } + /* again, determine if the text is mixed-directional or single-directional */ + dirct = directionFromFlags(); return dirct; } @@ -1547,49 +2352,57 @@ public class BidiBase { private byte checkExplicitLevels() { byte dirProp; int i; + int isolateCount = 0; + this.flags = 0; /* collect all directionalities in the text */ byte level; - int paraIndex = 0; + this.isolateCount = 0; for (i = 0; i < length; ++i) { if (levels[i] == 0) { - levels[i] = paraLevel; + levels[i] = paraLevel; } + + // for backward compatibility if (MAX_EXPLICIT_LEVEL < (levels[i]&0x7f)) { - if ((levels[i] & INTERNAL_LEVEL_OVERRIDE) != 0) { - levels[i] = (byte)(paraLevel|INTERNAL_LEVEL_OVERRIDE); + if ((levels[i] & LEVEL_OVERRIDE) != 0) { + levels[i] = (byte)(paraLevel|LEVEL_OVERRIDE); } else { levels[i] = paraLevel; } } + level = levels[i]; - dirProp = NoContextRTL(dirProps[i]); - if ((level & INTERNAL_LEVEL_OVERRIDE) != 0) { + dirProp = dirProps[i]; + if (dirProp == LRI || dirProp == RLI) { + isolateCount++; + if (isolateCount > this.isolateCount) + this.isolateCount = isolateCount; + } + else if (dirProp == PDI) { + isolateCount--; + } else if (dirProp == B) { + isolateCount = 0; + } + if ((level & LEVEL_OVERRIDE) != 0) { /* keep the override flag in levels[i] but adjust the flags */ - level &= ~INTERNAL_LEVEL_OVERRIDE; /* make the range check below simpler */ + level &= ~LEVEL_OVERRIDE; /* make the range check below simpler */ flags |= DirPropFlagO(level); } else { /* set the flags */ flags |= DirPropFlagE(level) | DirPropFlag(dirProp); } - if ((level < GetParaLevelAt(i) && !((0 == level) && (dirProp == B))) || - (MAX_EXPLICIT_LEVEL <level)) { + (MAX_EXPLICIT_LEVEL < level)) { /* level out of bounds */ throw new IllegalArgumentException("level " + level + - " out of bounds at index " + i); - } - if ((dirProp == B) && ((i + 1) < length)) { - if (!((text[i] == CR) && (text[i + 1] == LF))) { - paras[paraIndex++] = i + 1; - } + " out of bounds at " + i); } } - if ((flags&MASK_EMBEDDING) != 0) { + if ((flags & MASK_EMBEDDING) != 0) { flags |= DirPropFlagLR(paraLevel); } - /* determine if the text is mixed-directional or single-directional */ return directionFromFlags(); } @@ -1610,7 +2423,7 @@ public class BidiBase { /*********************************************************************/ /* Definitions and type for properties state tables */ /*********************************************************************/ - private static final int IMPTABPROPS_COLUMNS = 14; + private static final int IMPTABPROPS_COLUMNS = 16; private static final int IMPTABPROPS_RES = IMPTABPROPS_COLUMNS - 1; private static short GetStateProps(short cell) { return (short)(cell & 0x1f); @@ -1621,8 +2434,8 @@ public class BidiBase { private static final short groupProp[] = /* dirProp regrouped */ { - /* L R EN ES ET AN CS B S WS ON LRE LRO AL RLE RLO PDF NSM BN */ - 0, 1, 2, 7, 8, 3, 9, 6, 5, 4, 4, 10, 10, 12, 10, 10, 10, 11, 10 + /* L R EN ES ET AN CS B S WS ON LRE LRO AL RLE RLO PDF NSM BN FSI LRI RLI PDI ENL ENR */ + 0, 1, 2, 7, 8, 3, 9, 6, 5, 4, 4, 10, 10, 12, 10, 10, 10, 11, 10, 4, 4, 4, 4, 13, 14 }; private static final short _L = 0; private static final short _R = 1; @@ -1637,7 +2450,7 @@ public class BidiBase { /* PROPERTIES STATE TABLE */ /* */ /* In table impTabProps, */ - /* - the ON column regroups ON and WS */ + /* - the ON column regroups ON and WS, FSI, RLI, LRI and PDI */ /* - the BN column regroups BN, LRE, RLE, LRO, RLO, PDF */ /* - the Res column is the reduced property assigned to a run */ /* */ @@ -1668,25 +2481,31 @@ public class BidiBase { /* */ private static final short impTabProps[][] = { -/* L, R, EN, AN, ON, S, B, ES, ET, CS, BN, NSM, AL, Res */ -/* 0 Init */ { 1, 2, 4, 5, 7, 15, 17, 7, 9, 7, 0, 7, 3, _ON }, -/* 1 L */ { 1, 32+2, 32+4, 32+5, 32+7, 32+15, 32+17, 32+7, 32+9, 32+7, 1, 1, 32+3, _L }, -/* 2 R */ { 32+1, 2, 32+4, 32+5, 32+7, 32+15, 32+17, 32+7, 32+9, 32+7, 2, 2, 32+3, _R }, -/* 3 AL */ { 32+1, 32+2, 32+6, 32+6, 32+8, 32+16, 32+17, 32+8, 32+8, 32+8, 3, 3, 3, _R }, -/* 4 EN */ { 32+1, 32+2, 4, 32+5, 32+7, 32+15, 32+17, 64+10, 11, 64+10, 4, 4, 32+3, _EN }, -/* 5 AN */ { 32+1, 32+2, 32+4, 5, 32+7, 32+15, 32+17, 32+7, 32+9, 64+12, 5, 5, 32+3, _AN }, -/* 6 AL:EN/AN */ { 32+1, 32+2, 6, 6, 32+8, 32+16, 32+17, 32+8, 32+8, 64+13, 6, 6, 32+3, _AN }, -/* 7 ON */ { 32+1, 32+2, 32+4, 32+5, 7, 32+15, 32+17, 7, 64+14, 7, 7, 7, 32+3, _ON }, -/* 8 AL:ON */ { 32+1, 32+2, 32+6, 32+6, 8, 32+16, 32+17, 8, 8, 8, 8, 8, 32+3, _ON }, -/* 9 ET */ { 32+1, 32+2, 4, 32+5, 7, 32+15, 32+17, 7, 9, 7, 9, 9, 32+3, _ON }, -/*10 EN+ES/CS */ { 96+1, 96+2, 4, 96+5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7, 10, 128+7, 96+3, _EN }, -/*11 EN+ET */ { 32+1, 32+2, 4, 32+5, 32+7, 32+15, 32+17, 32+7, 11, 32+7, 11, 11, 32+3, _EN }, -/*12 AN+CS */ { 96+1, 96+2, 96+4, 5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7, 12, 128+7, 96+3, _AN }, -/*13 AL:EN/AN+CS */ { 96+1, 96+2, 6, 6, 128+8, 96+16, 96+17, 128+8, 128+8, 128+8, 13, 128+8, 96+3, _AN }, -/*14 ON+ET */ { 32+1, 32+2, 128+4, 32+5, 7, 32+15, 32+17, 7, 14, 7, 14, 14, 32+3, _ON }, -/*15 S */ { 32+1, 32+2, 32+4, 32+5, 32+7, 15, 32+17, 32+7, 32+9, 32+7, 15, 32+7, 32+3, _S }, -/*16 AL:S */ { 32+1, 32+2, 32+6, 32+6, 32+8, 16, 32+17, 32+8, 32+8, 32+8, 16, 32+8, 32+3, _S }, -/*17 B */ { 32+1, 32+2, 32+4, 32+5, 32+7, 32+15, 17, 32+7, 32+9, 32+7, 17, 32+7, 32+3, _B } +/* L, R, EN, AN, ON, S, B, ES, ET, CS, BN, NSM, AL, ENL, ENR, Res */ +/* 0 Init */ { 1, 2, 4, 5, 7, 15, 17, 7, 9, 7, 0, 7, 3, 18, 21, _ON }, +/* 1 L */ { 1, 32+2, 32+4, 32+5, 32+7, 32+15, 32+17, 32+7, 32+9, 32+7, 1, 1, 32+3, 32+18, 32+21, _L }, +/* 2 R */ { 32+1, 2, 32+4, 32+5, 32+7, 32+15, 32+17, 32+7, 32+9, 32+7, 2, 2, 32+3, 32+18, 32+21, _R }, +/* 3 AL */ { 32+1, 32+2, 32+6, 32+6, 32+8, 32+16, 32+17, 32+8, 32+8, 32+8, 3, 3, 3, 32+18, 32+21, _R }, +/* 4 EN */ { 32+1, 32+2, 4, 32+5, 32+7, 32+15, 32+17, 64+10, 11, 64+10, 4, 4, 32+3, 18, 21, _EN }, +/* 5 AN */ { 32+1, 32+2, 32+4, 5, 32+7, 32+15, 32+17, 32+7, 32+9, 64+12, 5, 5, 32+3, 32+18, 32+21, _AN }, +/* 6 AL:EN/AN */ { 32+1, 32+2, 6, 6, 32+8, 32+16, 32+17, 32+8, 32+8, 64+13, 6, 6, 32+3, 18, 21, _AN }, +/* 7 ON */ { 32+1, 32+2, 32+4, 32+5, 7, 32+15, 32+17, 7, 64+14, 7, 7, 7, 32+3, 32+18, 32+21, _ON }, +/* 8 AL:ON */ { 32+1, 32+2, 32+6, 32+6, 8, 32+16, 32+17, 8, 8, 8, 8, 8, 32+3, 32+18, 32+21, _ON }, +/* 9 ET */ { 32+1, 32+2, 4, 32+5, 7, 32+15, 32+17, 7, 9, 7, 9, 9, 32+3, 18, 21, _ON }, +/*10 EN+ES/CS */ { 96+1, 96+2, 4, 96+5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7, 10, 128+7, 96+3, 18, 21, _EN }, +/*11 EN+ET */ { 32+1, 32+2, 4, 32+5, 32+7, 32+15, 32+17, 32+7, 11, 32+7, 11, 11, 32+3, 18, 21, _EN }, +/*12 AN+CS */ { 96+1, 96+2, 96+4, 5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7, 12, 128+7, 96+3, 96+18, 96+21, _AN }, +/*13 AL:EN/AN+CS */ { 96+1, 96+2, 6, 6, 128+8, 96+16, 96+17, 128+8, 128+8, 128+8, 13, 128+8, 96+3, 18, 21, _AN }, +/*14 ON+ET */ { 32+1, 32+2, 128+4, 32+5, 7, 32+15, 32+17, 7, 14, 7, 14, 14, 32+3,128+18,128+21, _ON }, +/*15 S */ { 32+1, 32+2, 32+4, 32+5, 32+7, 15, 32+17, 32+7, 32+9, 32+7, 15, 32+7, 32+3, 32+18, 32+21, _S }, +/*16 AL:S */ { 32+1, 32+2, 32+6, 32+6, 32+8, 16, 32+17, 32+8, 32+8, 32+8, 16, 32+8, 32+3, 32+18, 32+21, _S }, +/*17 B */ { 32+1, 32+2, 32+4, 32+5, 32+7, 32+15, 17, 32+7, 32+9, 32+7, 17, 32+7, 32+3, 32+18, 32+21, _B }, +/*18 ENL */ { 32+1, 32+2, 18, 32+5, 32+7, 32+15, 32+17, 64+19, 20, 64+19, 18, 18, 32+3, 18, 21, _L }, +/*19 ENL+ES/CS */ { 96+1, 96+2, 18, 96+5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7, 19, 128+7, 96+3, 18, 21, _L }, +/*20 ENL+ET */ { 32+1, 32+2, 18, 32+5, 32+7, 32+15, 32+17, 32+7, 20, 32+7, 20, 20, 32+3, 18, 21, _L }, +/*21 ENR */ { 32+1, 32+2, 21, 32+5, 32+7, 32+15, 32+17, 64+22, 23, 64+22, 21, 21, 32+3, 18, 21, _AN }, +/*22 ENR+ES/CS */ { 96+1, 96+2, 21, 96+5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7, 22, 128+7, 96+3, 18, 21, _AN }, +/*23 ENR+ET */ { 32+1, 32+2, 21, 32+5, 32+7, 32+15, 32+17, 32+7, 23, 32+7, 23, 23, 32+3, 18, 21, _AN } }; /*********************************************************************/ @@ -1760,7 +2579,7 @@ public class BidiBase { /* */ private static final byte impTabL_DEFAULT[][] = /* Even paragraph level */ - /* In this table, conditional sequences receive the higher possible level + /* In this table, conditional sequences receive the lower possible level until proven otherwise. */ { @@ -1769,8 +2588,8 @@ public class BidiBase { /* 1 : R */ { 0, 1, 3, 3, 0x14, 0x14, 0, 1 }, /* 2 : AN */ { 0, 1, 0, 2, 0x15, 0x15, 0, 2 }, /* 3 : R+EN/AN */ { 0, 1, 3, 3, 0x14, 0x14, 0, 2 }, - /* 4 : R+ON */ { 0x20, 1, 3, 3, 4, 4, 0x20, 1 }, - /* 5 : AN+ON */ { 0x20, 1, 0x20, 2, 5, 5, 0x20, 1 } + /* 4 : R+ON */ { 0, 0x21, 0x33, 0x33, 4, 4, 0, 0 }, + /* 5 : AN+ON */ { 0, 0x21, 0, 0x32, 5, 5, 0, 0 } }; private static final byte impTabR_DEFAULT[][] = /* Odd paragraph level */ @@ -1787,20 +2606,20 @@ public class BidiBase { /* 5 : L+AN+ON */ { 1, 0, 1, 3, 5, 5, 0, 0 } }; - private static final short[] impAct0 = {0,1,2,3,4,5,6}; + private static final short[] impAct0 = {0,1,2,3,4}; private static final ImpTabPair impTab_DEFAULT = new ImpTabPair( impTabL_DEFAULT, impTabR_DEFAULT, impAct0, impAct0); private static final byte impTabL_NUMBERS_SPECIAL[][] = { /* Even paragraph level */ - /* In this table, conditional sequences receive the higher possible + /* In this table, conditional sequences receive the lower possible level until proven otherwise. */ /* L, R, EN, AN, ON, S, B, Res */ - /* 0 : init */ { 0, 2, 1, 1, 0, 0, 0, 0 }, - /* 1 : L+EN/AN */ { 0, 2, 1, 1, 0, 0, 0, 2 }, - /* 2 : R */ { 0, 2, 4, 4, 0x13, 0, 0, 1 }, - /* 3 : R+ON */ { 0x20, 2, 4, 4, 3, 3, 0x20, 1 }, + /* 0 : init */ { 0, 2, 0x11, 0x11, 0, 0, 0, 0 }, + /* 1 : L+EN/AN */ { 0, 0x42, 1, 1, 0, 0, 0, 0 }, + /* 2 : R */ { 0, 2, 4, 4, 0x13, 0x13, 0, 1 }, + /* 3 : R+ON */ { 0, 0x22, 0x34, 0x34, 3, 3, 0, 0 }, /* 4 : R+EN/AN */ { 0, 2, 4, 4, 0x13, 0x13, 0, 2 } }; private static final ImpTabPair impTab_NUMBERS_SPECIAL = new ImpTabPair( @@ -1874,7 +2693,7 @@ public class BidiBase { /* 5 : L+AN+ON */ { 0x21, 0x30, 6, 4, 5, 5, 0x30, 2 }, /* 6 : L+ON+EN */ { 0x21, 0x30, 6, 4, 3, 3, 0x30, 1 } }; - private static final short[] impAct1 = {0,1,11,12}; + private static final short[] impAct1 = {0,1,13,14}; private static final ImpTabPair impTab_INVERSE_LIKE_DIRECT = new ImpTabPair( impTabL_DEFAULT, impTabR_INVERSE_LIKE_DIRECT, impAct0, impAct1); @@ -1898,15 +2717,16 @@ public class BidiBase { /* 0 : init */ { 0x13, 0, 1, 1, 0, 0, 0, 0 }, /* 1 : R+EN/AN */ { 0x23, 0, 1, 1, 2, 0x40, 0, 1 }, /* 2 : R+EN/AN+ON */ { 0x23, 0, 1, 1, 2, 0x40, 0, 0 }, - /* 3 : L */ { 3 , 0, 3, 0x36, 0x14, 0x40, 0, 1 }, + /* 3 : L */ { 3, 0, 3, 0x36, 0x14, 0x40, 0, 1 }, /* 4 : L+ON */ { 0x53, 0x40, 5, 0x36, 4, 0x40, 0x40, 0 }, /* 5 : L+ON+EN */ { 0x53, 0x40, 5, 0x36, 4, 0x40, 0x40, 1 }, /* 6 : L+AN */ { 0x53, 0x40, 6, 6, 4, 0x40, 0x40, 3 } }; - private static final short impAct2[] = {0,1,7,8,9,10}; + private static final short[] impAct2 = {0,1,2,5,6,7,8}; + private static final short[] impAct3 = {0,1,9,10,11,12}; private static final ImpTabPair impTab_INVERSE_LIKE_DIRECT_WITH_MARKS = new ImpTabPair(impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS, - impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct0, impAct2); + impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct2, impAct3); private static final ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL = new ImpTabPair( impTabL_NUMBERS_SPECIAL, impTabR_INVERSE_LIKE_DIRECT, impAct0, impAct1); @@ -1923,14 +2743,15 @@ public class BidiBase { }; private static final ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS = new ImpTabPair(impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS, - impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct0, impAct2); + impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct2, impAct3); - private class LevState { + private static class LevState { byte[][] impTab; /* level table pointer */ short[] impAct; /* action map array */ int startON; /* start of ON sequence */ int startL2EN; /* start of level 2 sequence */ int lastStrongRTL; /* index of last found R or AL */ + int runStart; /* start position of the run */ short state; /* current state */ byte runLevel; /* run level before implicit solving */ } @@ -1962,6 +2783,22 @@ public class BidiBase { insertPoints.size++; } + private void setLevelsOutsideIsolates(int start, int limit, byte level) + { + byte dirProp; + int isolateCount = 0, k; + for (k = start; k < limit; k++) { + dirProp = dirProps[k]; + if (dirProp == PDI) + isolateCount--; + if (isolateCount == 0) { + levels[k] = level; + } + if (dirProp == LRI || dirProp == RLI) + isolateCount++; + } + } + /* perform rules (Wn), (Nn), and (In) on a run of the text ------------------ */ /* @@ -2003,7 +2840,17 @@ public class BidiBase { start = levState.startON; break; - case 3: /* L or S after possible relevant EN/AN */ + case 3: /* EN/AN after R+ON */ + level = (byte)(levState.runLevel + 1); + setLevelsOutsideIsolates(levState.startON, start0, level); + break; + + case 4: /* EN/AN before R for NUMBERS_SPECIAL */ + level = (byte)(levState.runLevel + 2); + setLevelsOutsideIsolates(levState.startON, start0, level); + break; + + case 5: /* L or S after possible relevant EN/AN */ /* check if we had EN after R/AL */ if (levState.startL2EN >= 0) { addPoint(levState.startL2EN, LRM_BEFORE); @@ -2039,7 +2886,7 @@ public class BidiBase { } break; - case 4: /* R/AL after possible relevant EN/AN */ + case 6: /* R/AL after possible relevant EN/AN */ /* just clean up */ if (insertPoints.points.length > 0) /* remove all non confirmed insert points */ @@ -2049,12 +2896,15 @@ public class BidiBase { levState.lastStrongRTL = limit - 1; break; - case 5: /* EN/AN after R/AL + possible cont */ + case 7: /* EN/AN after R/AL + possible cont */ /* check for real AN */ - if ((_prop == _AN) && (NoContextRTL(dirProps[start0]) == AN)) { + + if ((_prop == _AN) && (dirProps[start0] == AN) && + (reorderingMode != REORDER_INVERSE_FOR_NUMBERS_SPECIAL)) + { /* real AN */ if (levState.startL2EN == -1) { /* if no relevant EN already found */ - /* just note the righmost digit as a strong RTL */ + /* just note the rightmost digit as a strong RTL */ levState.lastStrongRTL = limit - 1; break; } @@ -2072,12 +2922,12 @@ public class BidiBase { } break; - case 6: /* note location of latest R/AL */ + case 8: /* note location of latest R/AL */ levState.lastStrongRTL = limit - 1; levState.startON = -1; break; - case 7: /* L after R+ON/EN/AN */ + case 9: /* L after R+ON/EN/AN */ /* include possible adjacent number on the left */ for (k = start0-1; k >= 0 && ((levels[k] & 1) == 0); k--) { } @@ -2088,14 +2938,14 @@ public class BidiBase { levState.startON = start0; break; - case 8: /* AN after L */ + case 10: /* AN after L */ /* AN numbers between L text on both sides may be trouble. */ /* tentatively bracket with LRMs; will be confirmed if followed by L */ addPoint(start0, LRM_BEFORE); /* add LRM before */ addPoint(start0, LRM_AFTER); /* add LRM after */ break; - case 9: /* R after L+ON/EN/AN */ + case 11: /* R after L+ON/EN/AN */ /* false alert, infirm LRMs around previous AN */ insertPoints.size=insertPoints.confirmed; if (_prop == _S) { /* add RLM before S */ @@ -2104,7 +2954,7 @@ public class BidiBase { } break; - case 10: /* L after L+ON/AN */ + case 12: /* L after L+ON/AN */ level = (byte)(levState.runLevel + addLevel); for (k=levState.startON; k < start0; k++) { if (levels[k] < level) { @@ -2115,7 +2965,7 @@ public class BidiBase { levState.startON = start0; break; - case 11: /* L after L+ON+EN/AN/ON */ + case 13: /* L after L+ON+EN/AN/ON */ level = levState.runLevel; for (k = start0-1; k >= levState.startON; k--) { if (levels[k] == level+3) { @@ -2134,7 +2984,7 @@ public class BidiBase { } break; - case 12: /* R after L+ON+EN/AN/ON */ + case 14: /* R after L+ON+EN/AN/ON */ level = (byte)(levState.runLevel+1); for (k = start0-1; k >= levState.startON; k--) { if (levels[k] > level) { @@ -2149,22 +2999,27 @@ public class BidiBase { } if ((addLevel) != 0 || (start < start0)) { level = (byte)(levState.runLevel + addLevel); - for (k = start; k < limit; k++) { - levels[k] = level; + if (start >= levState.runStart) { + for (k = start; k < limit; k++) { + levels[k] = level; + } + } else { + setLevelsOutsideIsolates(start, limit, level); } } } private void resolveImplicitLevels(int start, int limit, short sor, short eor) { + byte dirProp; LevState levState = new LevState(); int i, start1, start2; short oldStateImp, stateImp, actionImp; short gprop, resProp, cell; + boolean inverseRTL; short nextStrongProp = R; int nextStrongPos = -1; - /* check for RTL inverse Bidi mode */ /* FOOD FOR THOUGHT: in case of RTL inverse Bidi, it would make sense to * loop on the text characters from end to start. @@ -2172,29 +3027,78 @@ public class BidiBase { * actions) and different levels state tables (maybe very similar to the * LTR corresponding ones. */ - /* initialize for levels state table */ + inverseRTL=((start<lastArabicPos) && ((GetParaLevelAt(start) & 1)>0) && + (reorderingMode == REORDER_INVERSE_LIKE_DIRECT || + reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL)); + /* initialize for property and levels state table */ levState.startL2EN = -1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */ levState.lastStrongRTL = -1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */ - levState.state = 0; + levState.runStart = start; levState.runLevel = levels[start]; levState.impTab = impTabPair.imptab[levState.runLevel & 1]; levState.impAct = impTabPair.impact[levState.runLevel & 1]; - processPropertySeq(levState, sor, start, start); - /* initialize for property state table */ - if (dirProps[start] == NSM) { - stateImp = (short)(1 + sor); + + /* The isolates[] entries contain enough information to + resume the bidi algorithm in the same state as it was + when it was interrupted by an isolate sequence. */ + if (dirProps[start] == PDI) { + levState.startON = isolates[isolateCount].startON; + start1 = isolates[isolateCount].start1; + stateImp = isolates[isolateCount].stateImp; + levState.state = isolates[isolateCount].state; + isolateCount--; } else { - stateImp = 0; + levState.startON = -1; + start1 = start; + if (dirProps[start] == NSM) + stateImp = (short)(1 + sor); + else + stateImp = 0; + levState.state = 0; + processPropertySeq(levState, sor, start, start); } - start1 = start; - start2 = 0; + start2 = start; /* to make the Java compiler happy */ for (i = start; i <= limit; i++) { if (i >= limit) { + int k; + for (k = limit - 1; + k > start && + (DirPropFlag(dirProps[k]) & MASK_BN_EXPLICIT) != 0; + k--); + dirProp = dirProps[k]; + if (dirProp == LRI || dirProp == RLI) + break; /* no forced closing for sequence ending with LRI/RLI */ gprop = eor; } else { - short prop, prop1; - prop = NoContextRTL(dirProps[i]); + byte prop, prop1; + prop = dirProps[i]; + if (prop == B) + isolateCount = -1; /* current isolates stack entry == none */ + if (inverseRTL) { + if (prop == AL) { + /* AL before EN does not make it AN */ + prop = R; + } else if (prop == EN) { + if (nextStrongPos <= i) { + /* look for next strong char (L/R/AL) */ + int j; + nextStrongProp = R; /* set default */ + nextStrongPos = limit; + for (j = i+1; j < limit; j++) { + prop1 = dirProps[j]; + if (prop1 == L || prop1 == R || prop1 == AL) { + nextStrongProp = prop1; + nextStrongPos = j; + break; + } + } + } + if (nextStrongProp == AL) { + prop = AN; + } + } + } gprop = groupProp[prop]; } oldStateImp = stateImp; @@ -2230,8 +3134,24 @@ public class BidiBase { } } } - /* flush possible pending sequence, e.g. ON */ - processPropertySeq(levState, eor, limit, limit); + + /* look for the last char not a BN or LRE/RLE/LRO/RLO/PDF */ + for (i = limit - 1; + i > start && + (DirPropFlag(dirProps[i]) & MASK_BN_EXPLICIT) != 0; + i--); + dirProp = dirProps[i]; + if ((dirProp == LRI || dirProp == RLI) && limit < length) { + isolateCount++; + if (isolates[isolateCount] == null) + isolates[isolateCount] = new Isolate(); + isolates[isolateCount].stateImp = stateImp; + isolates[isolateCount].state = levState.state; + isolates[isolateCount].start1 = start1; + isolates[isolateCount].startON = levState.startON; + } + else + processPropertySeq(levState, eor, limit, limit); } /* perform (L1) and (X9) ---------------------------------------------------- */ @@ -2250,7 +3170,7 @@ public class BidiBase { i = trailingWSStart; while (i > 0) { /* reset a sequence of WS/BN before eop and B/S to the paragraph paraLevel */ - while (i > 0 && ((flag = DirPropFlagNC(dirProps[--i])) & MASK_WS) != 0) { + while (i > 0 && ((flag = DirPropFlag(dirProps[--i])) & MASK_WS) != 0) { if (orderParagraphsLTR && (flag & DirPropFlag(B)) != 0) { levels[i] = 0; } else { @@ -2261,7 +3181,7 @@ public class BidiBase { /* reset BN to the next character's paraLevel until B/S, which restarts above loop */ /* here, i+1 is guaranteed to be <length */ while (i > 0) { - flag = DirPropFlagNC(dirProps[--i]); + flag = DirPropFlag(dirProps[--i]); if ((flag & MASK_BN_EXPLICIT) != 0) { levels[i] = levels[i + 1]; } else if (orderParagraphsLTR && (flag & DirPropFlag(B)) != 0) { @@ -2276,6 +3196,10 @@ public class BidiBase { } } + private void setParaSuccess() { + paraBidi = this; /* mark successful setPara */ + } + private int Bidi_Min(int x, int y) { return x < y ? x : y; } @@ -2284,6 +3208,159 @@ public class BidiBase { return x >= 0 ? x : -x; } + void setParaRunsOnly(char[] parmText, byte parmParaLevel) { + int[] visualMap; + String visualText; + int saveLength, saveTrailingWSStart; + byte[] saveLevels; + byte saveDirection; + int i, j, visualStart, logicalStart, + oldRunCount, runLength, addedRuns, insertRemove, + start, limit, step, indexOddBit, logicalPos, + index, index1; + int saveOptions; + + reorderingMode = REORDER_DEFAULT; + int parmLength = parmText.length; + if (parmLength == 0) { + setPara(parmText, parmParaLevel, null); + reorderingMode = REORDER_RUNS_ONLY; + return; + } + /* obtain memory for mapping table and visual text */ + saveOptions = reorderingOptions; + if ((saveOptions & OPTION_INSERT_MARKS) > 0) { + reorderingOptions &= ~OPTION_INSERT_MARKS; + reorderingOptions |= OPTION_REMOVE_CONTROLS; + } + parmParaLevel &= 1; /* accept only 0 or 1 */ + setPara(parmText, parmParaLevel, null); + /* we cannot access directly levels since it is not yet set if + * direction is not MIXED + */ + saveLevels = new byte[this.length]; + System.arraycopy(getLevels(), 0, saveLevels, 0, this.length); + saveTrailingWSStart = trailingWSStart; + + /* FOOD FOR THOUGHT: instead of writing the visual text, we could use + * the visual map and the dirProps array to drive the second call + * to setPara (but must make provision for possible removal of + * Bidi controls. Alternatively, only use the dirProps array via + * customized classifier callback. + */ + visualText = writeReordered(DO_MIRRORING); + visualMap = getVisualMap(); + this.reorderingOptions = saveOptions; + saveLength = this.length; + saveDirection=this.direction; + + this.reorderingMode = REORDER_INVERSE_LIKE_DIRECT; + parmParaLevel ^= 1; + setPara(visualText, parmParaLevel, null); + BidiLine.getRuns(this); + /* check if some runs must be split, count how many splits */ + addedRuns = 0; + oldRunCount = this.runCount; + visualStart = 0; + for (i = 0; i < oldRunCount; i++, visualStart += runLength) { + runLength = runs[i].limit - visualStart; + if (runLength < 2) { + continue; + } + logicalStart = runs[i].start; + for (j = logicalStart+1; j < logicalStart+runLength; j++) { + index = visualMap[j]; + index1 = visualMap[j-1]; + if ((Bidi_Abs(index-index1)!=1) || (saveLevels[index]!=saveLevels[index1])) { + addedRuns++; + } + } + } + if (addedRuns > 0) { + getRunsMemory(oldRunCount + addedRuns); + if (runCount == 1) { + /* because we switch from UBiDi.simpleRuns to UBiDi.runs */ + runsMemory[0] = runs[0]; + } else { + System.arraycopy(runs, 0, runsMemory, 0, runCount); + } + runs = runsMemory; + runCount += addedRuns; + for (i = oldRunCount; i < runCount; i++) { + if (runs[i] == null) { + runs[i] = new BidiRun(0, 0, (byte)0); + } + } + } + /* split runs which are not consecutive in source text */ + int newI; + for (i = oldRunCount-1; i >= 0; i--) { + newI = i + addedRuns; + runLength = i==0 ? runs[0].limit : + runs[i].limit - runs[i-1].limit; + logicalStart = runs[i].start; + indexOddBit = runs[i].level & 1; + if (runLength < 2) { + if (addedRuns > 0) { + runs[newI].copyFrom(runs[i]); + } + logicalPos = visualMap[logicalStart]; + runs[newI].start = logicalPos; + runs[newI].level = (byte)(saveLevels[logicalPos] ^ indexOddBit); + continue; + } + if (indexOddBit > 0) { + start = logicalStart; + limit = logicalStart + runLength - 1; + step = 1; + } else { + start = logicalStart + runLength - 1; + limit = logicalStart; + step = -1; + } + for (j = start; j != limit; j += step) { + index = visualMap[j]; + index1 = visualMap[j+step]; + if ((Bidi_Abs(index-index1)!=1) || (saveLevels[index]!=saveLevels[index1])) { + logicalPos = Bidi_Min(visualMap[start], index); + runs[newI].start = logicalPos; + runs[newI].level = (byte)(saveLevels[logicalPos] ^ indexOddBit); + runs[newI].limit = runs[i].limit; + runs[i].limit -= Bidi_Abs(j - start) + 1; + insertRemove = runs[i].insertRemove & (LRM_AFTER|RLM_AFTER); + runs[newI].insertRemove = insertRemove; + runs[i].insertRemove &= ~insertRemove; + start = j + step; + addedRuns--; + newI--; + } + } + if (addedRuns > 0) { + runs[newI].copyFrom(runs[i]); + } + logicalPos = Bidi_Min(visualMap[start], visualMap[limit]); + runs[newI].start = logicalPos; + runs[newI].level = (byte)(saveLevels[logicalPos] ^ indexOddBit); + } + + cleanup1: + /* restore initial paraLevel */ + this.paraLevel ^= 1; + cleanup2: + /* restore real text */ + this.text = parmText; + this.length = saveLength; + this.originalLength = parmLength; + this.direction=saveDirection; + this.levels = saveLevels; + this.trailingWSStart = saveTrailingWSStart; + if (runCount > 1) { + this.direction = MIXED; + } + cleanup3: + this.reorderingMode = REORDER_RUNS_ONLY; + } + /** * Perform the Unicode Bidi algorithm. It is defined in the * <a href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>, @@ -2386,7 +3463,7 @@ public class BidiBase { * For example, in pure LTR text with numbers the numbers would get * a resolved level of 2 higher than the surrounding text according to * the algorithm. This implementation may set all resolved levels to - * the same value in such a case.<p> + * the same value in such a case. * * The text can be composed of multiple paragraphs. Occurrence of a block * separator in the text terminates a paragraph, and whatever comes next starts @@ -2421,9 +3498,9 @@ public class BidiBase { * (same index) character if the level has the * <code>LEVEL_OVERRIDE</code> bit set.<br><br> * Except for that bit, it must be - * {@code paraLevel<=embeddingLevels[]<=MAX_EXPLICIT_LEVEL}, + * <code>paraLevel<=embeddingLevels[]<=MAX_EXPLICIT_LEVEL</code>, * with one exception: a level of zero may be specified for a - * paragraph separator even if {@code paraLevel > 0} when multiple + * paragraph separator even if <code>paraLevel>0</code> when multiple * paragraphs are submitted in the same call to <code>setPara()</code>.<br><br> * <strong>Caution: </strong>A reference to this array, not a copy * of the levels, will be stored in the <code>Bidi</code> object; @@ -2444,22 +3521,28 @@ public class BidiBase { * @see #MAX_EXPLICIT_LEVEL * @stable ICU 3.8 */ - public void setPara(char[] chars, byte paraLevel, byte[] embeddingLevels) + void setPara(char[] chars, byte paraLevel, byte[] embeddingLevels) { /* check the argument values */ - if (paraLevel < INTERNAL_LEVEL_DEFAULT_LTR) { + if (paraLevel < LEVEL_DEFAULT_LTR) { verifyRange(paraLevel, 0, MAX_EXPLICIT_LEVEL + 1); } if (chars == null) { chars = new char[0]; } + /* special treatment for RUNS_ONLY mode */ + if (reorderingMode == REORDER_RUNS_ONLY) { + setParaRunsOnly(chars, paraLevel); + return; + } + /* initialize the Bidi object */ this.paraBidi = null; /* mark unfinished setPara */ this.text = chars; this.length = this.originalLength = this.resultLength = text.length; this.paraLevel = paraLevel; - this.direction = Bidi.DIRECTION_LEFT_TO_RIGHT; + this.direction = (byte)(paraLevel & 1); this.paraCount = 1; /* Allocate zero-length arrays instead of setting to null here; then @@ -2475,11 +3558,7 @@ public class BidiBase { /* * Save the original paraLevel if contextual; otherwise, set to 0. */ - if (IsDefaultLevel(paraLevel)) { - defaultParaLevel = paraLevel; - } else { - defaultParaLevel = 0; - } + defaultParaLevel = IsDefaultLevel(paraLevel) ? paraLevel : 0; if (length == 0) { /* @@ -2491,17 +3570,10 @@ public class BidiBase { this.paraLevel &= 1; defaultParaLevel = 0; } - if ((this.paraLevel & 1) != 0) { - flags = DirPropFlag(R); - direction = Bidi.DIRECTION_RIGHT_TO_LEFT; - } else { - flags = DirPropFlag(L); - direction = Bidi.DIRECTION_LEFT_TO_RIGHT; - } - + flags = DirPropFlagLR(paraLevel); runCount = 0; paraCount = 0; - paraBidi = this; /* mark successful setPara */ + setParaSuccess(); return; } @@ -2515,21 +3587,9 @@ public class BidiBase { getDirPropsMemory(length); dirProps = dirPropsMemory; getDirProps(); - /* the processed length may have changed if OPTION_STREAMING is set */ trailingWSStart = length; /* the levels[] will reflect the WS run */ - /* allocate paras memory */ - if (paraCount > 1) { - getInitialParasMemory(paraCount); - paras = parasMemory; - paras[paraCount - 1] = length; - } else { - /* initialize paras for single paragraph */ - paras = simpleParas; - simpleParas[0] = length; - } - /* are explicit levels specified? */ if (embeddingLevels == null) { /* no: determine explicit levels according to the (Xn) rules */ @@ -2542,28 +3602,62 @@ public class BidiBase { direction = checkExplicitLevels(); } + /* allocate isolate memory */ + if (isolateCount > 0) { + if (isolates == null || isolates.length < isolateCount) + isolates = new Isolate[isolateCount + 3]; /* keep some reserve */ + } + isolateCount = -1; /* current isolates stack entry == none */ + /* * The steps after (X9) in the Bidi algorithm are performed only if * the paragraph text has mixed directionality! */ switch (direction) { - case Bidi.DIRECTION_LEFT_TO_RIGHT: - /* make sure paraLevel is even */ - paraLevel = (byte)((paraLevel + 1) & ~1); - + case LTR: /* all levels are implicitly at paraLevel (important for getLevels()) */ trailingWSStart = 0; break; - case Bidi.DIRECTION_RIGHT_TO_LEFT: - /* make sure paraLevel is odd */ - paraLevel |= 1; - + case RTL: /* all levels are implicitly at paraLevel (important for getLevels()) */ trailingWSStart = 0; break; default: - this.impTabPair = impTab_DEFAULT; - + /* + * Choose the right implicit state table + */ + switch(reorderingMode) { + case REORDER_DEFAULT: + this.impTabPair = impTab_DEFAULT; + break; + case REORDER_NUMBERS_SPECIAL: + this.impTabPair = impTab_NUMBERS_SPECIAL; + break; + case REORDER_GROUP_NUMBERS_WITH_R: + this.impTabPair = impTab_GROUP_NUMBERS_WITH_R; + break; + case REORDER_RUNS_ONLY: + /* we should never get here */ + throw new InternalError("Internal ICU error in setPara"); + /* break; */ + case REORDER_INVERSE_NUMBERS_AS_L: + this.impTabPair = impTab_INVERSE_NUMBERS_AS_L; + break; + case REORDER_INVERSE_LIKE_DIRECT: + if ((reorderingOptions & OPTION_INSERT_MARKS) != 0) { + this.impTabPair = impTab_INVERSE_LIKE_DIRECT_WITH_MARKS; + } else { + this.impTabPair = impTab_INVERSE_LIKE_DIRECT; + } + break; + case REORDER_INVERSE_FOR_NUMBERS_SPECIAL: + if ((reorderingOptions & OPTION_INSERT_MARKS) != 0) { + this.impTabPair = impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS; + } else { + this.impTabPair = impTab_INVERSE_FOR_NUMBERS_SPECIAL; + } + break; + } /* * If there are no external levels specified and there * are no significant explicit level codes in the text, @@ -2601,7 +3695,7 @@ public class BidiBase { /* the values for this run's start are the same as for the previous run's end */ start = limit; level = nextLevel; - if ((start > 0) && (NoContextRTL(dirProps[start - 1]) == B)) { + if ((start > 0) && (dirProps[start - 1] == B)) { /* except if this is a new paragraph, then set sor = para level */ sor = GetLRFromLevel(GetParaLevelAt(start)); } else { @@ -2609,7 +3703,9 @@ public class BidiBase { } /* search for the limit of this run */ - while (++limit < length && levels[limit] == level) {} + while ((++limit < length) && + ((levels[limit] == level) || + ((DirPropFlag(dirProps[limit]) & MASK_BN_EXPLICIT) != 0))) {} /* get the correct level of the next run */ if (limit < length) { @@ -2619,7 +3715,7 @@ public class BidiBase { } /* determine eor from max(level, nextLevel); sor is last run's eor */ - if ((level & ~INTERNAL_LEVEL_OVERRIDE) < (nextLevel & ~INTERNAL_LEVEL_OVERRIDE)) { + if (NoOverride(level) < NoOverride(nextLevel)) { eor = GetLRFromLevel(nextLevel); } else { eor = GetLRFromLevel(level); @@ -2627,12 +3723,12 @@ public class BidiBase { /* if the run consists of overridden directional types, then there are no implicit types to be resolved */ - if ((level & INTERNAL_LEVEL_OVERRIDE) == 0) { + if ((level & LEVEL_OVERRIDE) == 0) { resolveImplicitLevels(start, limit, sor, eor); } else { /* remove the LEVEL_OVERRIDE flags */ do { - levels[start++] &= ~INTERNAL_LEVEL_OVERRIDE; + levels[start++] &= ~LEVEL_OVERRIDE; } while (start < limit); } } while (limit < length); @@ -2644,8 +3740,46 @@ public class BidiBase { break; } - resultLength += insertPoints.size; - paraBidi = this; /* mark successful setPara */ + /* add RLM for inverse Bidi with contextual orientation resolving + * to RTL which would not round-trip otherwise + */ + if ((defaultParaLevel > 0) && + ((reorderingOptions & OPTION_INSERT_MARKS) != 0) && + ((reorderingMode == REORDER_INVERSE_LIKE_DIRECT) || + (reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL))) { + int start, last; + byte level; + byte dirProp; + for (int i = 0; i < paraCount; i++) { + last = paras_limit[i] - 1; + level = paras_level[i]; + if (level == 0) + continue; /* LTR paragraph */ + start = i == 0 ? 0 : paras_limit[i - 1]; + for (int j = last; j >= start; j--) { + dirProp = dirProps[j]; + if (dirProp == L) { + if (j < last) { + while (dirProps[last] == B) { + last--; + } + } + addPoint(last, RLM_BEFORE); + break; + } + if ((DirPropFlag(dirProp) & MASK_R_AL) != 0) { + break; + } + } + } + } + + if ((reorderingOptions & OPTION_REMOVE_CONTROLS) != 0) { + resultLength -= controlCount; + } else { + resultLength += insertPoints.size; + } + setParaSuccess(); } /** @@ -2682,7 +3816,7 @@ public class BidiBase { * For example, in pure LTR text with numbers the numbers would get * a resolved level of 2 higher than the surrounding text according to * the algorithm. This implementation may set all resolved levels to - * the same value in such a case. + * the same value in such a case.<p> * * @param paragraph a paragraph of text with optional character and * paragraph attribute information @@ -2693,13 +3827,14 @@ public class BidiBase { byte paraLvl; char ch = paragraph.first(); Boolean runDirection = - (Boolean) paragraph.getAttribute(TextAttributeConstants.RUN_DIRECTION); + (Boolean) paragraph.getAttribute(TextAttributeConstants.RUN_DIRECTION); Object shaper = paragraph.getAttribute(TextAttributeConstants.NUMERIC_SHAPING); + if (runDirection == null) { - paraLvl = INTERNAL_LEVEL_DEFAULT_LTR; + paraLvl = LEVEL_DEFAULT_LTR; } else { paraLvl = (runDirection.equals(TextAttributeConstants.RUN_DIRECTION_LTR)) ? - (byte)Bidi.DIRECTION_LEFT_TO_RIGHT : (byte)Bidi.DIRECTION_RIGHT_TO_LEFT; + LTR : RTL; } byte[] lvls = null; @@ -2717,7 +3852,7 @@ public class BidiBase { /* no-op */ } else if (level < 0) { lvls = embeddingLevels; - embeddingLevels[i] = (byte)((0 - level) | INTERNAL_LEVEL_OVERRIDE); + embeddingLevels[i] = (byte)((0 - level) | LEVEL_OVERRIDE); } else { lvls = embeddingLevels; embeddingLevels[i] = level; @@ -2751,7 +3886,7 @@ public class BidiBase { * @see #setPara * @stable ICU 3.8 */ - private void orderParagraphsLTR(boolean ordarParaLTR) { + public void orderParagraphsLTR(boolean ordarParaLTR) { orderParagraphsLTR = ordarParaLTR; } @@ -2771,7 +3906,7 @@ public class BidiBase { * @see #MIXED * @stable ICU 3.8 */ - private byte getDirection() + public byte getDirection() { verifyValidParaOrLine(); return direction; @@ -2819,31 +3954,25 @@ public class BidiBase { } /** - * Get the index of a paragraph, given a position within the text. + * Retrieves the Bidi class for a given code point. + * <p>If a <code>BidiClassifier</code> is defined and returns a value + * other than <code>CLASS_DEFAULT</code>, that value is used; otherwise + * the default class determination mechanism is invoked.</p> * - * @param charIndex is the index of a character within the text, in the - * range <code>[0..getProcessedLength()-1]</code>. + * @param c The code point to get a Bidi class for. * - * @return The index of the paragraph containing the specified position, - * starting from 0. + * @return The Bidi class for the character <code>c</code> that is in effect + * for this <code>Bidi</code> instance. * - * @throws IllegalStateException if this call is not preceded by a successful - * call to <code>setPara</code> or <code>setLine</code> - * @throws IllegalArgumentException if charIndex is not within the legal range - * - * @see com.ibm.icu.text.BidiRun - * @see #getProcessedLength * @stable ICU 3.8 */ - public int getParagraphIndex(int charIndex) - { - verifyValidParaOrLine(); - BidiBase bidi = paraBidi; /* get Para object if Line object */ - verifyRange(charIndex, 0, bidi.length); - int paraIndex; - for (paraIndex = 0; charIndex >= bidi.paras[paraIndex]; paraIndex++) { - } - return paraIndex; + public int getCustomizedClass(int c) { + int dir; + + dir = bdp.getClass(c); + if (dir >= CHAR_DIRECTION_COUNT) + dir = ON; + return dir; } /** @@ -2891,7 +4020,7 @@ public class BidiBase { verifyRange(start, 0, limit); verifyRange(limit, 0, length+1); - return BidiLine.setLine(bidi, this, newBidi, newBidiBase, start, limit); + return BidiLine.setLine(this, newBidi, newBidiBase, start, limit); } /** @@ -2911,9 +4040,11 @@ public class BidiBase { */ public byte getLevelAt(int charIndex) { + // for backward compatibility if (charIndex < 0 || charIndex >= length) { return (byte)getBaseLevel(); } + verifyValidParaOrLine(); verifyRange(charIndex, 0, length); return BidiLine.getLevelAt(this, charIndex); @@ -2932,7 +4063,7 @@ public class BidiBase { * call to <code>setPara</code> or <code>setLine</code> * @stable ICU 3.8 */ - private byte[] getLevels() + byte[] getLevels() { verifyValidParaOrLine(); if (length <= 0) { @@ -2962,6 +4093,78 @@ public class BidiBase { return runCount; } + /** + * + * Get a <code>BidiRun</code> object according to its index. BidiRun methods + * may be used to retrieve the run's logical start, length and level, + * which can be even for an LTR run or odd for an RTL run. + * In an RTL run, the character at the logical start is + * visually on the right of the displayed run. + * The length is the number of characters in the run.<p> + * <code>countRuns()</code> is normally called + * before the runs are retrieved. + * + * <p> + * Example: + * <pre> + * Bidi bidi = new Bidi(); + * String text = "abc 123 DEFG xyz"; + * bidi.setPara(text, Bidi.RTL, null); + * int i, count=bidi.countRuns(), logicalStart, visualIndex=0, length; + * BidiRun run; + * for (i = 0; i < count; ++i) { + * run = bidi.getVisualRun(i); + * logicalStart = run.getStart(); + * length = run.getLength(); + * if (Bidi.LTR == run.getEmbeddingLevel()) { + * do { // LTR + * show_char(text.charAt(logicalStart++), visualIndex++); + * } while (--length > 0); + * } else { + * logicalStart += length; // logicalLimit + * do { // RTL + * show_char(text.charAt(--logicalStart), visualIndex++); + * } while (--length > 0); + * } + * } + * </pre> + * <p> + * Note that in right-to-left runs, code like this places + * second surrogates before first ones (which is generally a bad idea) + * and combining characters before base characters. + * <p> + * Use of <code>{@link #writeReordered}</code>, optionally with the + * <code>{@link #KEEP_BASE_COMBINING}</code> option, can be considered in + * order to avoid these issues. + * + * @param runIndex is the number of the run in visual order, in the + * range <code>[0..countRuns()-1]</code>. + * + * @return a BidiRun object containing the details of the run. The + * directionality of the run is + * <code>LTR==0</code> or <code>RTL==1</code>, + * never <code>MIXED</code>. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to <code>setPara</code> or <code>setLine</code> + * @throws IllegalArgumentException if <code>runIndex</code> is not in + * the range <code>0<=runIndex<countRuns()</code> + * + * @see #countRuns() + * @see com.ibm.icu.text.BidiRun + * @see com.ibm.icu.text.BidiRun#getStart() + * @see com.ibm.icu.text.BidiRun#getLength() + * @see com.ibm.icu.text.BidiRun#getEmbeddingLevel() + * @stable ICU 3.8 + */ + BidiRun getVisualRun(int runIndex) + { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + verifyRange(runIndex, 0, runCount); + return BidiLine.getVisualRun(this, runIndex); + } + /** * Get a visual-to-logical index map (array) for the characters in the * <code>Bidi</code> (paragraph or line) object. @@ -3027,15 +4230,6 @@ public class BidiBase { return BidiLine.reorderVisual(levels); } - /** - * Constant indicating that the base direction depends on the first strong - * directional character in the text according to the Unicode Bidirectional - * Algorithm. If no strong directional character is present, the base - * direction is left-to-right. - * @stable ICU 3.8 - */ - private static final int INTERNAL_DIRECTION_DEFAULT_LEFT_TO_RIGHT = 0x7e; - /** * Constant indicating that the base direction depends on the first strong * directional character in the text according to the Unicode Bidirectional @@ -3043,7 +4237,7 @@ public class BidiBase { * direction is right-to-left. * @stable ICU 3.8 */ - private static final int INTERMAL_DIRECTION_DEFAULT_RIGHT_TO_LEFT = 0x7f; + public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = LEVEL_DEFAULT_RTL; /** * Create Bidi from the given text, embedding, and direction information. @@ -3080,27 +4274,27 @@ public class BidiBase { * @stable ICU 3.8 */ public BidiBase(char[] text, - int textStart, - byte[] embeddings, - int embStart, - int paragraphLength, - int flags) - { + int textStart, + byte[] embeddings, + int embStart, + int paragraphLength, + int flags) + { this(0, 0); byte paraLvl; switch (flags) { case Bidi.DIRECTION_LEFT_TO_RIGHT: default: - paraLvl = Bidi.DIRECTION_LEFT_TO_RIGHT; + paraLvl = LTR; break; case Bidi.DIRECTION_RIGHT_TO_LEFT: - paraLvl = Bidi.DIRECTION_RIGHT_TO_LEFT; + paraLvl = RTL; break; case Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT: - paraLvl = INTERNAL_LEVEL_DEFAULT_LTR; + paraLvl = LEVEL_DEFAULT_LTR; break; case Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT: - paraLvl = INTERNAL_LEVEL_DEFAULT_RTL; + paraLvl = LEVEL_DEFAULT_RTL; break; } byte[] paraEmbeddings; @@ -3112,7 +4306,7 @@ public class BidiBase { for (int i = 0; i < paragraphLength; i++) { lev = embeddings[i + embStart]; if (lev < 0) { - lev = (byte)((- lev) | INTERNAL_LEVEL_OVERRIDE); + lev = (byte)((- lev) | LEVEL_OVERRIDE); } else if (lev == 0) { lev = paraLvl; if (paraLvl > MAX_EXPLICIT_LEVEL) { @@ -3122,13 +4316,10 @@ public class BidiBase { paraEmbeddings[i] = lev; } } - if (textStart == 0 && embStart == 0 && paragraphLength == text.length) { - setPara(text, paraLvl, paraEmbeddings); - } else { - char[] paraText = new char[paragraphLength]; - System.arraycopy(text, textStart, paraText, 0, paragraphLength); - setPara(paraText, paraLvl, paraEmbeddings); - } + + char[] paraText = new char[paragraphLength]; + System.arraycopy(text, textStart, paraText, 0, paragraphLength); + setPara(paraText, paraLvl, paraEmbeddings); } /** @@ -3148,7 +4339,7 @@ public class BidiBase { } /** - * Return true if the line is all left-to-right text and the base direction + * Return true if the line is all left-to-right text and the base direction * is left-to-right. * * @return true if the line is all left-to-right text and the base direction @@ -3160,7 +4351,7 @@ public class BidiBase { */ public boolean isLeftToRight() { - return (getDirection() == Bidi.DIRECTION_LEFT_TO_RIGHT && (paraLevel & 1) == 0); + return (getDirection() == LTR && (paraLevel & 1) == 0); } /** @@ -3176,7 +4367,7 @@ public class BidiBase { */ public boolean isRightToLeft() { - return (getDirection() == Bidi.DIRECTION_RIGHT_TO_LEFT && (paraLevel & 1) == 1); + return (getDirection() == RTL && (paraLevel & 1) == 1); } /** @@ -3191,7 +4382,7 @@ public class BidiBase { */ public boolean baseIsLeftToRight() { - return (getParaLevel() == Bidi.DIRECTION_LEFT_TO_RIGHT); + return (getParaLevel() == LTR); } /** @@ -3212,8 +4403,8 @@ public class BidiBase { /** * Compute the logical to visual run mapping */ - private void getLogicalToVisualRunsMap() - { + void getLogicalToVisualRunsMap() + { if (isGoodLogicalToVisualRunsMap) { return; } @@ -3231,9 +4422,8 @@ public class BidiBase { for (i = 0; i < count; i++) { logicalToVisualRunsMap[i] = (int)(keys[i] & 0x00000000FFFFFFFF); } - keys = null; isGoodLogicalToVisualRunsMap = true; - } + } /** * Return the level of the nth logical run in this line. @@ -3252,9 +4442,12 @@ public class BidiBase { { verifyValidParaOrLine(); BidiLine.getRuns(this); + + // for backward compatibility if (run < 0 || run >= runCount) { return getParaLevel(); } + getLogicalToVisualRunsMap(); return runs[logicalToVisualRunsMap[run]].level; } @@ -3277,12 +4470,14 @@ public class BidiBase { { verifyValidParaOrLine(); BidiLine.getRuns(this); + + // for backward compatibility if (runCount == 1) { return 0; } else if (run == runCount) { return length; } - verifyIndex(run, 0, runCount); + getLogicalToVisualRunsMap(); return runs[logicalToVisualRunsMap[run]].start; } @@ -3306,10 +4501,12 @@ public class BidiBase { { verifyValidParaOrLine(); BidiLine.getRuns(this); + + // for backward compatibility if (runCount == 1) { return length; } - verifyIndex(run, 0, runCount); + getLogicalToVisualRunsMap(); int idx = logicalToVisualRunsMap[run]; int len = idx == 0 ? runs[idx].limit : @@ -3336,7 +4533,7 @@ public class BidiBase { int start, int limit) { - final int RTLMask = (1 << Bidi.DIRECTION_RIGHT_TO_LEFT | + final int RTLMask = (1 << R | 1 << AL | 1 << RLE | 1 << RLO | @@ -3346,6 +4543,7 @@ public class BidiBase { throw new IllegalArgumentException("Value start " + start + " is out of range 0 to " + limit); } + for (int i = start; i < limit; ++i) { if (Character.isHighSurrogate(text[i]) && i < (limit-1) && Character.isLowSurrogate(text[i+1])) { @@ -3356,6 +4554,7 @@ public class BidiBase { return true; } } + return false; } @@ -3382,8 +4581,9 @@ public class BidiBase { int objectStart, int count) { + // for backward compatibility if (0 > levelStart || levels.length <= levelStart) { - throw new IllegalArgumentException("Value levelStart " + + throw new IllegalArgumentException("Value levelStart " + levelStart + " is out of range 0 to " + (levels.length-1)); } @@ -3397,6 +4597,7 @@ public class BidiBase { levelStart + " is out of range 0 to " + (objects.length - objectStart)); } + byte[] reorderLevels = new byte[count]; System.arraycopy(levels, levelStart, reorderLevels, 0, count); int[] indexMap = reorderVisual(reorderLevels); @@ -3407,6 +4608,74 @@ public class BidiBase { } } + /** + * Take a <code>Bidi</code> object containing the reordering + * information for a piece of text (one or more paragraphs) set by + * <code>setPara()</code> or for a line of text set by <code>setLine()</code> + * and return a string containing the reordered text. + * + * <p>The text may have been aliased (only a reference was stored + * without copying the contents), thus it must not have been modified + * since the <code>setPara()</code> call.</p> + * + * This method preserves the integrity of characters with multiple + * code units and (optionally) combining characters. + * Characters in RTL runs can be replaced by mirror-image characters + * in the returned string. Note that "real" mirroring has to be done in a + * rendering engine by glyph selection and that for many "mirrored" + * characters there are no Unicode characters as mirror-image equivalents. + * There are also options to insert or remove Bidi control + * characters; see the descriptions of the return value and the + * <code>options</code> parameter, and of the option bit flags. + * + * @param options A bit set of options for the reordering that control + * how the reordered text is written. + * The options include mirroring the characters on a code + * point basis and inserting LRM characters, which is used + * especially for transforming visually stored text + * to logically stored text (although this is still an + * imperfect implementation of an "inverse Bidi" algorithm + * because it uses the "forward Bidi" algorithm at its core). + * The available options are: + * <code>DO_MIRRORING</code>, + * <code>INSERT_LRM_FOR_NUMERIC</code>, + * <code>KEEP_BASE_COMBINING</code>, + * <code>OUTPUT_REVERSE</code>, + * <code>REMOVE_BIDI_CONTROLS</code>, + * <code>STREAMING</code> + * + * @return The reordered text. + * If the <code>INSERT_LRM_FOR_NUMERIC</code> option is set, then + * the length of the returned string could be as large as + * <code>getLength()+2*countRuns()</code>.<br> + * If the <code>REMOVE_BIDI_CONTROLS</code> option is set, then the + * length of the returned string may be less than + * <code>getLength()</code>.<br> + * If none of these options is set, then the length of the returned + * string will be exactly <code>getProcessedLength()</code>. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to <code>setPara</code> or <code>setLine</code> + * + * @see #DO_MIRRORING + * @see #INSERT_LRM_FOR_NUMERIC + * @see #KEEP_BASE_COMBINING + * @see #OUTPUT_REVERSE + * @see #REMOVE_BIDI_CONTROLS + * @see #OPTION_STREAMING + * @see #getProcessedLength + * @stable ICU 3.8 + */ + public String writeReordered(int options) + { + verifyValidParaOrLine(); + if (length == 0) { + /* nothing to do */ + return ""; + } + return BidiWriter.writeReordered(this, options); + } + /** * Display the bidi internal state, used in debugging. */ @@ -3507,4 +4776,5 @@ public class BidiBase { } } } + } diff --git a/jdk/src/java.base/share/classes/sun/text/bidi/BidiLine.java b/jdk/src/java.base/share/classes/sun/text/bidi/BidiLine.java index 1d54867ad42..721a14bdfaf 100644 --- a/jdk/src/java.base/share/classes/sun/text/bidi/BidiLine.java +++ b/jdk/src/java.base/share/classes/sun/text/bidi/BidiLine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * 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,17 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* - ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ +******************************************************************************* +* Copyright (C) 2001-2014, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ /* Written by Simon Montagu, Matitiahu Allouche * (ported from C code written by Markus W. Scherer) */ @@ -42,7 +38,7 @@ package sun.text.bidi; import java.text.Bidi; import java.util.Arrays; -public final class BidiLine { +final class BidiLine { /* * General remarks about the functions in this file: @@ -122,13 +118,13 @@ public final class BidiLine { level of B chars from 0 to paraLevel in getLevels when orderParagraphsLTR==TRUE */ - if (BidiBase.NoContextRTL(dirProps[start - 1]) == BidiBase.B) { + if (dirProps[start - 1] == BidiBase.B) { bidiBase.trailingWSStart = start; /* currently == bidiBase.length */ return; } /* go backwards across all WS, BN, explicit codes */ while (start > 0 && - (BidiBase.DirPropFlagNC(dirProps[start - 1]) & BidiBase.MASK_WS) != 0) { + (BidiBase.DirPropFlag(dirProps[start - 1]) & BidiBase.MASK_WS) != 0) { --start; } @@ -140,13 +136,11 @@ public final class BidiLine { bidiBase.trailingWSStart=start; } - public static Bidi setLine(Bidi bidi, BidiBase paraBidi, - Bidi newBidi, BidiBase newBidiBase, - int start, int limit) { + static Bidi setLine(BidiBase paraBidi, + Bidi newBidi, BidiBase lineBidi, + int start, int limit) { int length; - BidiBase lineBidi = newBidiBase; - /* set the values in lineBidi from its paraBidi parent */ /* class members are already initialized to 0 */ // lineBidi.paraBidi = null; /* mark unfinished setLine */ @@ -161,6 +155,8 @@ public final class BidiLine { lineBidi.paraLevel = paraBidi.GetParaLevelAt(start); lineBidi.paraCount = paraBidi.paraCount; lineBidi.runs = new BidiRun[0]; + lineBidi.reorderingMode = paraBidi.reorderingMode; + lineBidi.reorderingOptions = paraBidi.reorderingOptions; if (paraBidi.controlCount > 0) { int j; for (j = start; j < limit; j++) { @@ -206,7 +202,7 @@ public final class BidiLine { setTrailingWSStart(lineBidi); trailingWSStart = lineBidi.trailingWSStart; - /* recalculate lineBidi.direction */ + /* recalculate lineBidiBase.direction */ if (trailingWSStart == 0) { /* all levels are at paraLevel */ lineBidi.direction = (byte)(lineBidi.paraLevel & 1); @@ -260,7 +256,8 @@ public final class BidiLine { } } - newBidiBase.paraBidi = paraBidi; /* mark successful setLine */ + lineBidi.paraBidi = paraBidi; /* mark successful setLine */ + return newBidi; } @@ -303,30 +300,19 @@ public final class BidiLine { return bidiBase.levels; } - static BidiRun getLogicalRun(BidiBase bidiBase, int logicalPosition) - { - /* this is done based on runs rather than on levels since levels have - a special interpretation when REORDER_RUNS_ONLY - */ - BidiRun newRun = new BidiRun(), iRun; - getRuns(bidiBase); - int runCount = bidiBase.runCount; - int visualStart = 0, logicalLimit = 0; - iRun = bidiBase.runs[0]; + static BidiRun getVisualRun(BidiBase bidiBase, int runIndex) { + int start = bidiBase.runs[runIndex].start; + int limit; + byte level = bidiBase.runs[runIndex].level; - for (int i = 0; i < runCount; i++) { - iRun = bidiBase.runs[i]; - logicalLimit = iRun.start + iRun.limit - visualStart; - if ((logicalPosition >= iRun.start) && - (logicalPosition < logicalLimit)) { - break; - } - visualStart = iRun.limit; + if (runIndex > 0) { + limit = start + + bidiBase.runs[runIndex].limit - + bidiBase.runs[runIndex - 1].limit; + } else { + limit = start + bidiBase.runs[0].limit; } - newRun.start = iRun.start; - newRun.limit = logicalLimit; - newRun.level = iRun.level; - return newRun; + return new BidiRun(start, limit, level); } /* in trivial cases there is only one trivial run; called by getRuns() */ @@ -502,7 +488,7 @@ public final class BidiLine { int length = bidiBase.length, limit; byte[] levels = bidiBase.levels; int i, runCount; - byte level = BidiBase.INTERNAL_LEVEL_DEFAULT_LTR; /* initialize with no valid level */ + byte level = -1; /* initialize with no valid level */ /* * If there are WS characters at the end of the line * and the run preceding them has a level different from @@ -651,7 +637,7 @@ public final class BidiLine { maxLevel = 0; for (start = levels.length; start>0; ) { level = levels[--start]; - if (level > BidiBase.MAX_EXPLICIT_LEVEL + 1) { + if (level < 0 || level > (BidiBase.MAX_EXPLICIT_LEVEL + 1)) { return null; } if (level < minLevel) { diff --git a/jdk/src/java.base/share/classes/sun/text/bidi/BidiRun.java b/jdk/src/java.base/share/classes/sun/text/bidi/BidiRun.java index c0323834c60..d6a28e88db4 100644 --- a/jdk/src/java.base/share/classes/sun/text/bidi/BidiRun.java +++ b/jdk/src/java.base/share/classes/sun/text/bidi/BidiRun.java @@ -55,7 +55,7 @@ package sun.text.bidi; * * @see com.ibm.icu.text.Bidi */ -public class BidiRun { +class BidiRun { int start; /* first logical position of the run */ int limit; /* last visual position of the run +1 */ @@ -106,7 +106,7 @@ public class BidiRun { /** * Get level of run */ - public byte getEmbeddingLevel() + byte getEmbeddingLevel() { return level; } diff --git a/jdk/src/java.base/share/classes/sun/text/bidi/BidiWriter.java b/jdk/src/java.base/share/classes/sun/text/bidi/BidiWriter.java new file mode 100644 index 00000000000..5c6d84d3182 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/bidi/BidiWriter.java @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* +******************************************************************************* +* Copyright (C) 2001-2010, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ +/* Written by Simon Montagu, Matitiahu Allouche + * (ported from C code written by Markus W. Scherer) + */ + +package sun.text.bidi; + +import sun.text.normalizer.UCharacter; +import sun.text.normalizer.UTF16; + +final class BidiWriter { + + /** Bidi control code points */ + static final char LRM_CHAR = 0x200e; + static final char RLM_CHAR = 0x200f; + static final int MASK_R_AL = (1 << UCharacter.RIGHT_TO_LEFT | + 1 << UCharacter.RIGHT_TO_LEFT_ARABIC); + + private static boolean IsCombining(int type) { + return ((1<<type & + (1<<UCharacter.NON_SPACING_MARK | + 1<<UCharacter.COMBINING_SPACING_MARK | + 1<<UCharacter.ENCLOSING_MARK)) != 0); + } + + /* + * When we have OUTPUT_REVERSE set on writeReordered(), then we + * semantically write RTL runs in reverse and later reverse them again. + * Instead, we actually write them in forward order to begin with. + * However, if the RTL run was to be mirrored, we need to mirror here now + * since the implicit second reversal must not do it. + * It looks strange to do mirroring in LTR output, but it is only because + * we are writing RTL output in reverse. + */ + private static String doWriteForward(String src, int options) { + /* optimize for several combinations of options */ + switch(options&(BidiBase.REMOVE_BIDI_CONTROLS|BidiBase.DO_MIRRORING)) { + case 0: { + /* simply return the LTR run */ + return src; + } + case BidiBase.DO_MIRRORING: { + StringBuffer dest = new StringBuffer(src.length()); + + /* do mirroring */ + int i=0; + int c; + + do { + c = UTF16.charAt(src, i); + i += UTF16.getCharCount(c); + UTF16.append(dest, UCharacter.getMirror(c)); + } while(i < src.length()); + return dest.toString(); + } + case BidiBase.REMOVE_BIDI_CONTROLS: { + StringBuilder dest = new StringBuilder(src.length()); + + /* copy the LTR run and remove any Bidi control characters */ + int i = 0; + char c; + do { + c = src.charAt(i++); + if(!BidiBase.IsBidiControlChar(c)) { + dest.append(c); + } + } while(i < src.length()); + return dest.toString(); + } + default: { + StringBuffer dest = new StringBuffer(src.length()); + + /* remove Bidi control characters and do mirroring */ + int i = 0; + int c; + do { + c = UTF16.charAt(src, i); + i += UTF16.getCharCount(c); + if(!BidiBase.IsBidiControlChar(c)) { + UTF16.append(dest, UCharacter.getMirror(c)); + } + } while(i < src.length()); + return dest.toString(); + } + } /* end of switch */ + } + + private static String doWriteForward(char[] text, int start, int limit, + int options) { + return doWriteForward(new String(text, start, limit - start), options); + } + + static String writeReverse(String src, int options) { + /* + * RTL run - + * + * RTL runs need to be copied to the destination in reverse order + * of code points, not code units, to keep Unicode characters intact. + * + * The general strategy for this is to read the source text + * in backward order, collect all code units for a code point + * (and optionally following combining characters, see below), + * and copy all these code units in ascending order + * to the destination for this run. + * + * Several options request whether combining characters + * should be kept after their base characters, + * whether Bidi control characters should be removed, and + * whether characters should be replaced by their mirror-image + * equivalent Unicode characters. + */ + StringBuffer dest = new StringBuffer(src.length()); + + /* optimize for several combinations of options */ + switch (options & + (BidiBase.REMOVE_BIDI_CONTROLS | + BidiBase.DO_MIRRORING | + BidiBase.KEEP_BASE_COMBINING)) { + + case 0: + /* + * With none of the "complicated" options set, the destination + * run will have the same length as the source run, + * and there is no mirroring and no keeping combining characters + * with their base characters. + * + * XXX: or dest = UTF16.reverse(new StringBuffer(src)); + */ + + int srcLength = src.length(); + + /* preserve character integrity */ + do { + /* i is always after the last code unit known to need to be kept + * in this segment */ + int i = srcLength; + + /* collect code units for one base character */ + srcLength -= UTF16.getCharCount(UTF16.charAt(src, + srcLength - 1)); + + /* copy this base character */ + dest.append(src.substring(srcLength, i)); + } while(srcLength > 0); + break; + + case BidiBase.KEEP_BASE_COMBINING: + /* + * Here, too, the destination + * run will have the same length as the source run, + * and there is no mirroring. + * We do need to keep combining characters with their base + * characters. + */ + srcLength = src.length(); + + /* preserve character integrity */ + do { + /* i is always after the last code unit known to need to be kept + * in this segment */ + int c; + int i = srcLength; + + /* collect code units and modifier letters for one base + * character */ + do { + c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + } while(srcLength > 0 && IsCombining(UCharacter.getType(c))); + + /* copy this "user character" */ + dest.append(src.substring(srcLength, i)); + } while(srcLength > 0); + break; + + default: + /* + * With several "complicated" options set, this is the most + * general and the slowest copying of an RTL run. + * We will do mirroring, remove Bidi controls, and + * keep combining characters with their base characters + * as requested. + */ + srcLength = src.length(); + + /* preserve character integrity */ + do { + /* i is always after the last code unit known to need to be kept + * in this segment */ + int i = srcLength; + + /* collect code units for one base character */ + int c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + if ((options & BidiBase.KEEP_BASE_COMBINING) != 0) { + /* collect modifier letters for this base character */ + while(srcLength > 0 && IsCombining(UCharacter.getType(c))) { + c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + } + } + + if ((options & BidiBase.REMOVE_BIDI_CONTROLS) != 0 && + BidiBase.IsBidiControlChar(c)) { + /* do not copy this Bidi control character */ + continue; + } + + /* copy this "user character" */ + int j = srcLength; + if((options & BidiBase.DO_MIRRORING) != 0) { + /* mirror only the base character */ + c = UCharacter.getMirror(c); + UTF16.append(dest, c); + j += UTF16.getCharCount(c); + } + dest.append(src.substring(j, i)); + } while(srcLength > 0); + break; + } /* end of switch */ + + return dest.toString(); + } + + static String doWriteReverse(char[] text, int start, int limit, int options) { + return writeReverse(new String(text, start, limit - start), options); + } + + static String writeReordered(BidiBase bidi, int options) { + int run, runCount; + StringBuilder dest; + char[] text = bidi.text; + runCount = bidi.countRuns(); + + /* + * Option "insert marks" implies BidiBase.INSERT_LRM_FOR_NUMERIC if the + * reordering mode (checked below) is appropriate. + */ + if ((bidi.reorderingOptions & BidiBase.OPTION_INSERT_MARKS) != 0) { + options |= BidiBase.INSERT_LRM_FOR_NUMERIC; + options &= ~BidiBase.REMOVE_BIDI_CONTROLS; + } + /* + * Option "remove controls" implies BidiBase.REMOVE_BIDI_CONTROLS + * and cancels BidiBase.INSERT_LRM_FOR_NUMERIC. + */ + if ((bidi.reorderingOptions & BidiBase.OPTION_REMOVE_CONTROLS) != 0) { + options |= BidiBase.REMOVE_BIDI_CONTROLS; + options &= ~BidiBase.INSERT_LRM_FOR_NUMERIC; + } + /* + * If we do not perform the "inverse Bidi" algorithm, then we + * don't need to insert any LRMs, and don't need to test for it. + */ + if ((bidi.reorderingMode != BidiBase.REORDER_INVERSE_NUMBERS_AS_L) && + (bidi.reorderingMode != BidiBase.REORDER_INVERSE_LIKE_DIRECT) && + (bidi.reorderingMode != BidiBase.REORDER_INVERSE_FOR_NUMBERS_SPECIAL) && + (bidi.reorderingMode != BidiBase.REORDER_RUNS_ONLY)) { + options &= ~BidiBase.INSERT_LRM_FOR_NUMERIC; + } + dest = new StringBuilder((options & BidiBase.INSERT_LRM_FOR_NUMERIC) != 0 ? + bidi.length * 2 : bidi.length); + /* + * Iterate through all visual runs and copy the run text segments to + * the destination, according to the options. + * + * The tests for where to insert LRMs ignore the fact that there may be + * BN codes or non-BMP code points at the beginning and end of a run; + * they may insert LRMs unnecessarily but the tests are faster this way + * (this would have to be improved for UTF-8). + */ + if ((options & BidiBase.OUTPUT_REVERSE) == 0) { + /* forward output */ + if ((options & BidiBase.INSERT_LRM_FOR_NUMERIC) == 0) { + /* do not insert Bidi controls */ + for (run = 0; run < runCount; ++run) { + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + dest.append(doWriteForward(text, bidiRun.start, + bidiRun.limit, + options & ~BidiBase.DO_MIRRORING)); + } else { + dest.append(doWriteReverse(text, bidiRun.start, + bidiRun.limit, options)); + } + } + } else { + /* insert Bidi controls for "inverse Bidi" */ + byte[] dirProps = bidi.dirProps; + char uc; + int markFlag; + + for (run = 0; run < runCount; ++run) { + BidiRun bidiRun = bidi.getVisualRun(run); + markFlag=0; + /* check if something relevant in insertPoints */ + markFlag = bidi.runs[run].insertRemove; + if (markFlag < 0) { /* bidi controls count */ + markFlag = 0; + } + if (bidiRun.isEvenRun()) { + if (bidi.isInverse() && + dirProps[bidiRun.start] != BidiBase.L) { + markFlag |= BidiBase.LRM_BEFORE; + } + if ((markFlag & BidiBase.LRM_BEFORE) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_BEFORE) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + dest.append(doWriteForward(text, + bidiRun.start, bidiRun.limit, + options & ~BidiBase.DO_MIRRORING)); + + if (bidi.isInverse() && + dirProps[bidiRun.limit - 1] != BidiBase.L) { + markFlag |= BidiBase.LRM_AFTER; + } + if ((markFlag & BidiBase.LRM_AFTER) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_AFTER) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + } else { /* RTL run */ + if (bidi.isInverse() && + !bidi.testDirPropFlagAt(MASK_R_AL, + bidiRun.limit - 1)) { + markFlag |= BidiBase.RLM_BEFORE; + } + if ((markFlag & BidiBase.LRM_BEFORE) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_BEFORE) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + dest.append(doWriteReverse(text, bidiRun.start, + bidiRun.limit, options)); + + if(bidi.isInverse() && + (MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.start])) == 0) { + markFlag |= BidiBase.RLM_AFTER; + } + if ((markFlag & BidiBase.LRM_AFTER) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_AFTER) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + } + } + } + } else { + /* reverse output */ + if((options & BidiBase.INSERT_LRM_FOR_NUMERIC) == 0) { + /* do not insert Bidi controls */ + for(run = runCount; --run >= 0; ) { + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + dest.append(doWriteReverse(text, + bidiRun.start, bidiRun.limit, + options & ~BidiBase.DO_MIRRORING)); + } else { + dest.append(doWriteForward(text, bidiRun.start, + bidiRun.limit, options)); + } + } + } else { + /* insert Bidi controls for "inverse Bidi" */ + + byte[] dirProps = bidi.dirProps; + + for (run = runCount; --run >= 0; ) { + /* reverse output */ + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + if (dirProps[bidiRun.limit - 1] != BidiBase.L) { + dest.append(LRM_CHAR); + } + + dest.append(doWriteReverse(text, bidiRun.start, + bidiRun.limit, options & ~BidiBase.DO_MIRRORING)); + + if (dirProps[bidiRun.start] != BidiBase.L) { + dest.append(LRM_CHAR); + } + } else { + if ((MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.start])) == 0) { + dest.append(RLM_CHAR); + } + + dest.append(doWriteForward(text, bidiRun.start, + bidiRun.limit, options)); + + if ((MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.limit - 1])) == 0) { + dest.append(RLM_CHAR); + } + } + } + } + } + + return dest.toString(); + } +} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/BMPSet.java b/jdk/src/java.base/share/classes/sun/text/normalizer/BMPSet.java new file mode 100644 index 00000000000..2c2c8fb2165 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/BMPSet.java @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* + ****************************************************************************** + * + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + * + ****************************************************************************** + */ + +package sun.text.normalizer; + +import sun.text.normalizer.UnicodeSet.SpanCondition; + +/** + * Helper class for frozen UnicodeSets, implements contains() and span() optimized for BMP code points. + * + * Latin-1: Look up bytes. + * 2-byte characters: Bits organized vertically. + * 3-byte characters: Use zero/one/mixed data per 64-block in U+0000..U+FFFF, with mixed for illegal ranges. + * Supplementary characters: Call contains() on the parent set. + */ +final class BMPSet { + + /** + * One boolean ('true' or 'false') per Latin-1 character. + */ + private boolean[] latin1Contains; + + /** + * One bit per code point from U+0000..U+07FF. The bits are organized vertically; consecutive code points + * correspond to the same bit positions in consecutive table words. With code point parts lead=c{10..6} + * trail=c{5..0} it is set.contains(c)==(table7FF[trail] bit lead) + * + * Bits for 0..7F (non-shortest forms) are set to the result of contains(FFFD) for faster validity checking at + * runtime. + */ + private int[] table7FF; + + /** + * One bit per 64 BMP code points. The bits are organized vertically; consecutive 64-code point blocks + * correspond to the same bit position in consecutive table words. With code point parts lead=c{15..12} + * t1=c{11..6} test bits (lead+16) and lead in bmpBlockBits[t1]. If the upper bit is 0, then the lower bit + * indicates if contains(c) for all code points in the 64-block. If the upper bit is 1, then the block is mixed + * and set.contains(c) must be called. + * + * Bits for 0..7FF (non-shortest forms) and D800..DFFF are set to the result of contains(FFFD) for faster + * validity checking at runtime. + */ + private int[] bmpBlockBits; + + /** + * Inversion list indexes for restricted binary searches in findCodePoint(), from findCodePoint(U+0800, U+1000, + * U+2000, .., U+F000, U+10000). U+0800 is the first 3-byte-UTF-8 code point. Code points below U+0800 are + * always looked up in the bit tables. The last pair of indexes is for finding supplementary code points. + */ + private int[] list4kStarts; + + /** + * The inversion list of the parent set, for the slower contains() implementation for mixed BMP blocks and for + * supplementary code points. The list is terminated with list[listLength-1]=0x110000. + */ + private final int[] list; + private final int listLength; // length used; list may be longer to minimize reallocs + + public BMPSet(final int[] parentList, int parentListLength) { + list = parentList; + listLength = parentListLength; + latin1Contains = new boolean[0x100]; + table7FF = new int[64]; + bmpBlockBits = new int[64]; + list4kStarts = new int[18]; + + /* + * Set the list indexes for binary searches for U+0800, U+1000, U+2000, .., U+F000, U+10000. U+0800 is the + * first 3-byte-UTF-8 code point. Lower code points are looked up in the bit tables. The last pair of + * indexes is for finding supplementary code points. + */ + list4kStarts[0] = findCodePoint(0x800, 0, listLength - 1); + int i; + for (i = 1; i <= 0x10; ++i) { + list4kStarts[i] = findCodePoint(i << 12, list4kStarts[i - 1], listLength - 1); + } + list4kStarts[0x11] = listLength - 1; + + initBits(); + } + + public boolean contains(int c) { + if (c <= 0xff) { + return (latin1Contains[c]); + } else if (c <= 0x7ff) { + return ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0); + } else if (c < 0xd800 || (c >= 0xe000 && c <= 0xffff)) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + return (0 != twoBits); + } else { + // Look up the code point in its 4k block of code points. + return containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1]); + } + } else if (c <= 0x10ffff) { + // surrogate or supplementary code point + return containsSlow(c, list4kStarts[0xd], list4kStarts[0x11]); + } else { + // Out-of-range code points get false, consistent with long-standing + // behavior of UnicodeSet.contains(c). + return false; + } + } + + /** + * Span the initial substring for which each character c has spanCondition==contains(c). It must be + * spanCondition==0 or 1. + * + * @param start The start index + * @param outCount If not null: Receives the number of code points in the span. + * @return the limit (exclusive end) of the span + * + * NOTE: to reduce the overhead of function call to contains(c), it is manually inlined here. Check for + * sufficient length for trail unit for each surrogate pair. Handle single surrogates as surrogate code points + * as usual in ICU. + */ + public final int span(CharSequence s, int start, SpanCondition spanCondition, + OutputInt outCount) { + char c, c2; + int i = start; + int limit = s.length(); + int numSupplementary = 0; + if (SpanCondition.NOT_CONTAINED != spanCondition) { + // span + while (i < limit) { + c = s.charAt(i); + if (c <= 0xff) { + if (!latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) == 0) { + break; + } + } else if (c < 0xd800 || + c >= 0xdc00 || (i + 1) == limit || (c2 = s.charAt(i + 1)) < 0xdc00 || c2 >= 0xe000) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits == 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (!containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + if (!containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + ++numSupplementary; + ++i; + } + ++i; + } + } else { + // span not + while (i < limit) { + c = s.charAt(i); + if (c <= 0xff) { + if (latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0) { + break; + } + } else if (c < 0xd800 || + c >= 0xdc00 || (i + 1) == limit || (c2 = s.charAt(i + 1)) < 0xdc00 || c2 >= 0xe000) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits != 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + if (containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + ++numSupplementary; + ++i; + } + ++i; + } + } + if (outCount != null) { + int spanLength = i - start; + outCount.value = spanLength - numSupplementary; // number of code points + } + return i; + } + + /** + * Symmetrical with span(). + * Span the trailing substring for which each character c has spanCondition==contains(c). It must be s.length >= + * limit and spanCondition==0 or 1. + * + * @return The string index which starts the span (i.e. inclusive). + */ + public final int spanBack(CharSequence s, int limit, SpanCondition spanCondition) { + char c, c2; + + if (SpanCondition.NOT_CONTAINED != spanCondition) { + // span + for (;;) { + c = s.charAt(--limit); + if (c <= 0xff) { + if (!latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) == 0) { + break; + } + } else if (c < 0xd800 || + c < 0xdc00 || 0 == limit || (c2 = s.charAt(limit - 1)) < 0xd800 || c2 >= 0xdc00) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits == 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (!containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + if (!containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + --limit; + } + if (0 == limit) { + return 0; + } + } + } else { + // span not + for (;;) { + c = s.charAt(--limit); + if (c <= 0xff) { + if (latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0) { + break; + } + } else if (c < 0xd800 || + c < 0xdc00 || 0 == limit || (c2 = s.charAt(limit - 1)) < 0xd800 || c2 >= 0xdc00) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits != 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + if (containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + --limit; + } + if (0 == limit) { + return 0; + } + } + } + return limit + 1; + } + + /** + * Set bits in a bit rectangle in "vertical" bit organization. start<limit<=0x800 + */ + private static void set32x64Bits(int[] table, int start, int limit) { + assert (64 == table.length); + int lead = start >> 6; // Named for UTF-8 2-byte lead byte with upper 5 bits. + int trail = start & 0x3f; // Named for UTF-8 2-byte trail byte with lower 6 bits. + + // Set one bit indicating an all-one block. + int bits = 1 << lead; + if ((start + 1) == limit) { // Single-character shortcut. + table[trail] |= bits; + return; + } + + int limitLead = limit >> 6; + int limitTrail = limit & 0x3f; + + if (lead == limitLead) { + // Partial vertical bit column. + while (trail < limitTrail) { + table[trail++] |= bits; + } + } else { + // Partial vertical bit column, + // followed by a bit rectangle, + // followed by another partial vertical bit column. + if (trail > 0) { + do { + table[trail++] |= bits; + } while (trail < 64); + ++lead; + } + if (lead < limitLead) { + bits = ~((1 << lead) - 1); + if (limitLead < 0x20) { + bits &= (1 << limitLead) - 1; + } + for (trail = 0; trail < 64; ++trail) { + table[trail] |= bits; + } + } + // limit<=0x800. If limit==0x800 then limitLead=32 and limitTrail=0. + // In that case, bits=1<<limitLead == 1<<0 == 1 + // (because Java << uses only the lower 5 bits of the shift operand) + // but the bits value is not used because trail<limitTrail is already false. + bits = 1 << limitLead; + for (trail = 0; trail < limitTrail; ++trail) { + table[trail] |= bits; + } + } + } + + private void initBits() { + int start, limit; + int listIndex = 0; + + // Set latin1Contains[]. + do { + start = list[listIndex++]; + if (listIndex < listLength) { + limit = list[listIndex++]; + } else { + limit = 0x110000; + } + if (start >= 0x100) { + break; + } + do { + latin1Contains[start++] = true; + } while (start < limit && start < 0x100); + } while (limit <= 0x100); + + // Set table7FF[]. + while (start < 0x800) { + set32x64Bits(table7FF, start, limit <= 0x800 ? limit : 0x800); + if (limit > 0x800) { + start = 0x800; + break; + } + + start = list[listIndex++]; + if (listIndex < listLength) { + limit = list[listIndex++]; + } else { + limit = 0x110000; + } + } + + // Set bmpBlockBits[]. + int minStart = 0x800; + while (start < 0x10000) { + if (limit > 0x10000) { + limit = 0x10000; + } + + if (start < minStart) { + start = minStart; + } + if (start < limit) { // Else: Another range entirely in a known mixed-value block. + if (0 != (start & 0x3f)) { + // Mixed-value block of 64 code points. + start >>= 6; + bmpBlockBits[start & 0x3f] |= 0x10001 << (start >> 6); + start = (start + 1) << 6; // Round up to the next block boundary. + minStart = start; // Ignore further ranges in this block. + } + if (start < limit) { + if (start < (limit & ~0x3f)) { + // Multiple all-ones blocks of 64 code points each. + set32x64Bits(bmpBlockBits, start >> 6, limit >> 6); + } + + if (0 != (limit & 0x3f)) { + // Mixed-value block of 64 code points. + limit >>= 6; + bmpBlockBits[limit & 0x3f] |= 0x10001 << (limit >> 6); + limit = (limit + 1) << 6; // Round up to the next block boundary. + minStart = limit; // Ignore further ranges in this block. + } + } + } + + if (limit == 0x10000) { + break; + } + + start = list[listIndex++]; + if (listIndex < listLength) { + limit = list[listIndex++]; + } else { + limit = 0x110000; + } + } + } + + /** + * Same as UnicodeSet.findCodePoint(int c) except that the binary search is restricted for finding code + * points in a certain range. + * + * For restricting the search for finding in the range start..end, pass in lo=findCodePoint(start) and + * hi=findCodePoint(end) with 0<=lo<=hi<len. findCodePoint(c) defaults to lo=0 and hi=len-1. + * + * @param c + * a character in a subrange of MIN_VALUE..MAX_VALUE + * @param lo + * The lowest index to be returned. + * @param hi + * The highest index to be returned. + * @return the smallest integer i in the range lo..hi, inclusive, such that c < list[i] + */ + private int findCodePoint(int c, int lo, int hi) { + /* Examples: + findCodePoint(c) + set list[] c=0 1 3 4 7 8 + === ============== =========== + [] [110000] 0 0 0 0 0 0 + [\u0000-\u0003] [0, 4, 110000] 1 1 1 2 2 2 + [\u0004-\u0007] [4, 8, 110000] 0 0 0 1 1 2 + [:Any:] [0, 110000] 1 1 1 1 1 1 + */ + + // Return the smallest i such that c < list[i]. Assume + // list[len - 1] == HIGH and that c is legal (0..HIGH-1). + if (c < list[lo]) + return lo; + // High runner test. c is often after the last range, so an + // initial check for this condition pays off. + if (lo >= hi || c >= list[hi - 1]) + return hi; + // invariant: c >= list[lo] + // invariant: c < list[hi] + for (;;) { + int i = (lo + hi) >>> 1; + if (i == lo) { + break; // Found! + } else if (c < list[i]) { + hi = i; + } else { + lo = i; + } + } + return hi; + } + + private final boolean containsSlow(int c, int lo, int hi) { + return (0 != (findCodePoint(c, lo, hi) & 1)); + } +} + diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/CharTrie.java b/jdk/src/java.base/share/classes/sun/text/normalizer/CharTrie.java index 9726e8932f6..3609ace58ef 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/CharTrie.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/CharTrie.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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,22 +22,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* - ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* + ****************************************************************************** + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ****************************************************************************** */ package sun.text.normalizer; -import java.io.InputStream; import java.io.DataInputStream; +import java.io.InputStream; import java.io.IOException; /** @@ -73,120 +69,17 @@ public class CharTrie extends Trie throw new IllegalArgumentException( "Data given does not belong to a char trie."); } - m_friendAgent_ = new FriendAgent(); - } - - /** - * Make a dummy CharTrie. - * A dummy trie is an empty runtime trie, used when a real data trie cannot - * be loaded. - * - * The trie always returns the initialValue, - * or the leadUnitValue for lead surrogate code points. - * The Latin-1 part is always set up to be linear. - * - * @param initialValue the initial value that is set for all code points - * @param leadUnitValue the value for lead surrogate code _units_ that do not - * have associated supplementary data - * @param dataManipulate object which provides methods to parse the char data - */ - public CharTrie(int initialValue, int leadUnitValue, DataManipulate dataManipulate) { - super(new char[BMP_INDEX_LENGTH+SURROGATE_BLOCK_COUNT], HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_, dataManipulate); - - int dataLength, latin1Length, i, limit; - char block; - - /* calculate the actual size of the dummy trie data */ - - /* max(Latin-1, block 0) */ - dataLength=latin1Length= INDEX_STAGE_1_SHIFT_<=8 ? 256 : DATA_BLOCK_LENGTH; - if(leadUnitValue!=initialValue) { - dataLength+=DATA_BLOCK_LENGTH; - } - m_data_=new char[dataLength]; - m_dataLength_=dataLength; - - m_initialValue_=(char)initialValue; - - /* fill the index and data arrays */ - - /* indexes are preset to 0 (block 0) */ - - /* Latin-1 data */ - for(i=0; i<latin1Length; ++i) { - m_data_[i]=(char)initialValue; - } - - if(leadUnitValue!=initialValue) { - /* indexes for lead surrogate code units to the block after Latin-1 */ - block=(char)(latin1Length>>INDEX_STAGE_2_SHIFT_); - i=0xd800>>INDEX_STAGE_1_SHIFT_; - limit=0xdc00>>INDEX_STAGE_1_SHIFT_; - for(; i<limit; ++i) { - m_index_[i]=block; - } - - /* data for lead surrogate code units */ - limit=latin1Length+DATA_BLOCK_LENGTH; - for(i=latin1Length; i<limit; ++i) { - m_data_[i]=(char)leadUnitValue; - } - } - - m_friendAgent_ = new FriendAgent(); - } - - /** - * Java friend implementation - */ - public class FriendAgent - { - /** - * Gives out the index array of the trie - * @return index array of trie - */ - public char[] getPrivateIndex() - { - return m_index_; - } - /** - * Gives out the data array of the trie - * @return data array of trie - */ - public char[] getPrivateData() - { - return m_data_; - } - /** - * Gives out the data offset in the trie - * @return data offset in the trie - */ - public int getPrivateInitialValue() - { - return m_initialValue_; - } } // public methods -------------------------------------------------- /** - * Java friend implementation - * To store the index and data array into the argument. - * @param friend java friend UCharacterProperty object to store the array + * Gets the value associated with the codepoint. + * If no value is associated with the codepoint, a default value will be + * returned. + * @param ch codepoint + * @return offset to data */ - public void putIndexData(UCharacterProperty friend) - { - friend.setIndexData(m_friendAgent_); - } - - /** - * Gets the value associated with the codepoint. - * If no value is associated with the codepoint, a default value will be - * returned. - * @param ch codepoint - * @return offset to data - * @draft 2.1 - */ public final char getCodePointValue(int ch) { int offset; @@ -215,52 +108,12 @@ public class CharTrie extends Trie * This method does not guarantee correct results for trail surrogates. * @param ch lead surrogate character * @return data value - * @draft 2.1 */ public final char getLeadValue(char ch) { return m_data_[getLeadOffset(ch)]; } - /** - * Get the value associated with a pair of surrogates. - * @param lead a lead surrogate - * @param trail a trail surrogate - * @draft 2.1 - */ - public final char getSurrogateValue(char lead, char trail) - { - int offset = getSurrogateOffset(lead, trail); - if (offset > 0) { - return m_data_[offset]; - } - return m_initialValue_; - } - - /** - * <p>Get a value from a folding offset (from the value of a lead surrogate) - * and a trail surrogate.</p> - * <p>If the - * @param leadvalue value associated with the lead surrogate which contains - * the folding offset - * @param trail surrogate - * @return trie data value associated with the trail character - * @draft 2.1 - */ - public final char getTrailValue(int leadvalue, char trail) - { - if (m_dataManipulate_ == null) { - throw new NullPointerException( - "The field DataManipulate in this Trie is null"); - } - int offset = m_dataManipulate_.getFoldingOffset(leadvalue); - if (offset > 0) { - return m_data_[getRawOffset(offset, - (char)(trail & SURROGATE_MASK_))]; - } - return m_initialValue_; - } - // protected methods ----------------------------------------------- /** @@ -309,41 +162,14 @@ public class CharTrie extends Trie return -1; } - /** - * Gets the value at the argument index. - * For use internally in TrieIterator. - * @param index value at index will be retrieved - * @return 32 bit value - * @see com.ibm.icu.impl.TrieIterator - * @draft 2.1 - */ - protected final int getValue(int index) - { - return m_data_[index]; - } - - /** - * Gets the default initial value - * @return 32 bit value - * @draft 2.1 - */ - protected final int getInitialValue() - { - return m_initialValue_; - } - // private data members -------------------------------------------- /** - * Default value - */ + * Default value + */ private char m_initialValue_; /** - * Array of char data - */ - private char m_data_[]; - /** - * Agent for friends + * Array of char data */ - private FriendAgent m_friendAgent_; + private char m_data_[]; } diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/CharacterIteratorWrapper.java b/jdk/src/java.base/share/classes/sun/text/normalizer/CharacterIteratorWrapper.java index dd2202d5122..674cc9465dd 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/CharacterIteratorWrapper.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/CharacterIteratorWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.text.CharacterIterator; * @author ram */ -public class CharacterIteratorWrapper extends UCharacterIterator { +class CharacterIteratorWrapper extends UCharacterIterator { private CharacterIterator iterator; @@ -111,7 +111,6 @@ public class CharacterIteratorWrapper extends UCharacterIterator { iterator.setIndex(index); } - //// for StringPrep /** * @see UCharacterIterator#getText(char[]) */ diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/FilteredNormalizer2.java b/jdk/src/java.base/share/classes/sun/text/normalizer/FilteredNormalizer2.java new file mode 100644 index 00000000000..60e35b7c620 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/FilteredNormalizer2.java @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* +******************************************************************************* +* Copyright (C) 2009-2014, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ +package sun.text.normalizer; + +import java.io.IOException; + +/** + * Normalization filtered by a UnicodeSet. + * Normalizes portions of the text contained in the filter set and leaves + * portions not contained in the filter set unchanged. + * Filtering is done via UnicodeSet.span(..., UnicodeSet.SpanCondition.SIMPLE). + * Not-in-the-filter text is treated as "is normalized" and "quick check yes". + * This class implements all of (and only) the Normalizer2 API. + * An instance of this class is unmodifiable/immutable. + * @stable ICU 4.4 + * @author Markus W. Scherer + */ +class FilteredNormalizer2 extends Normalizer2 { + + /** + * Constructs a filtered normalizer wrapping any Normalizer2 instance + * and a filter set. + * Both are aliased and must not be modified or deleted while this object + * is used. + * The filter set should be frozen; otherwise the performance will suffer greatly. + * @param n2 wrapped Normalizer2 instance + * @param filterSet UnicodeSet which determines the characters to be normalized + * @stable ICU 4.4 + */ + public FilteredNormalizer2(Normalizer2 n2, UnicodeSet filterSet) { + norm2=n2; + set=filterSet; + } + + /** + * {@inheritDoc} + * @stable ICU 4.4 + */ + @Override + public StringBuilder normalize(CharSequence src, StringBuilder dest) { + if(dest==src) { + throw new IllegalArgumentException(); + } + dest.setLength(0); + normalize(src, dest, UnicodeSet.SpanCondition.SIMPLE); + return dest; + } + + /** + * {@inheritDoc} + * @stable ICU 4.6 + */ + @Override + public Appendable normalize(CharSequence src, Appendable dest) { + if(dest==src) { + throw new IllegalArgumentException(); + } + return normalize(src, dest, UnicodeSet.SpanCondition.SIMPLE); + } + + /** + * {@inheritDoc} + * @stable ICU 4.4 + */ + @Override + public StringBuilder normalizeSecondAndAppend( + StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, true); + } + + /** + * {@inheritDoc} + * @stable ICU 4.4 + */ + @Override + public StringBuilder append(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, false); + } + + /** + * {@inheritDoc} + * @stable ICU 4.6 + */ + @Override + public String getDecomposition(int c) { + return set.contains(c) ? norm2.getDecomposition(c) : null; + } + + /** + * {@inheritDoc} + * @stable ICU 49 + */ + @Override + public int getCombiningClass(int c) { + return set.contains(c) ? norm2.getCombiningClass(c) : 0; + } + + /** + * {@inheritDoc} + * @stable ICU 4.4 + */ + @Override + public boolean isNormalized(CharSequence s) { + UnicodeSet.SpanCondition spanCondition=UnicodeSet.SpanCondition.SIMPLE; + for(int prevSpanLimit=0; prevSpanLimit<s.length();) { + int spanLimit=set.span(s, prevSpanLimit, spanCondition); + if(spanCondition==UnicodeSet.SpanCondition.NOT_CONTAINED) { + spanCondition=UnicodeSet.SpanCondition.SIMPLE; + } else { + if(!norm2.isNormalized(s.subSequence(prevSpanLimit, spanLimit))) { + return false; + } + spanCondition=UnicodeSet.SpanCondition.NOT_CONTAINED; + } + prevSpanLimit=spanLimit; + } + return true; + } + + /** + * {@inheritDoc} + * @stable ICU 4.4 + */ + @Override + public int spanQuickCheckYes(CharSequence s) { + UnicodeSet.SpanCondition spanCondition=UnicodeSet.SpanCondition.SIMPLE; + for(int prevSpanLimit=0; prevSpanLimit<s.length();) { + int spanLimit=set.span(s, prevSpanLimit, spanCondition); + if(spanCondition==UnicodeSet.SpanCondition.NOT_CONTAINED) { + spanCondition=UnicodeSet.SpanCondition.SIMPLE; + } else { + int yesLimit= + prevSpanLimit+ + norm2.spanQuickCheckYes(s.subSequence(prevSpanLimit, spanLimit)); + if(yesLimit<spanLimit) { + return yesLimit; + } + spanCondition=UnicodeSet.SpanCondition.NOT_CONTAINED; + } + prevSpanLimit=spanLimit; + } + return s.length(); + } + + /** + * {@inheritDoc} + * @stable ICU 4.4 + */ + @Override + public boolean hasBoundaryBefore(int c) { + return !set.contains(c) || norm2.hasBoundaryBefore(c); + } + + // Internal: No argument checking, and appends to dest. + // Pass as input spanCondition the one that is likely to yield a non-zero + // span length at the start of src. + // For set=[:age=3.2:], since almost all common characters were in Unicode 3.2, + // UnicodeSet.SpanCondition.SIMPLE should be passed in for the start of src + // and UnicodeSet.SpanCondition.NOT_CONTAINED should be passed in if we continue after + // an in-filter prefix. + private Appendable normalize(CharSequence src, Appendable dest, + UnicodeSet.SpanCondition spanCondition) { + // Don't throw away destination buffer between iterations. + StringBuilder tempDest=new StringBuilder(); + try { + for(int prevSpanLimit=0; prevSpanLimit<src.length();) { + int spanLimit=set.span(src, prevSpanLimit, spanCondition); + int spanLength=spanLimit-prevSpanLimit; + if(spanCondition==UnicodeSet.SpanCondition.NOT_CONTAINED) { + if(spanLength!=0) { + dest.append(src, prevSpanLimit, spanLimit); + } + spanCondition=UnicodeSet.SpanCondition.SIMPLE; + } else { + if(spanLength!=0) { + // Not norm2.normalizeSecondAndAppend() because we do not want + // to modify the non-filter part of dest. + dest.append(norm2.normalize(src.subSequence(prevSpanLimit, spanLimit), tempDest)); + } + spanCondition=UnicodeSet.SpanCondition.NOT_CONTAINED; + } + prevSpanLimit=spanLimit; + } + } catch(IOException e) { + throw new InternalError(e.toString(), e); + } + return dest; + } + + private StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second, + boolean doNormalize) { + if(first==second) { + throw new IllegalArgumentException(); + } + if(first.length()==0) { + if(doNormalize) { + return normalize(second, first); + } else { + return first.append(second); + } + } + // merge the in-filter suffix of the first string with the in-filter prefix of the second + int prefixLimit=set.span(second, 0, UnicodeSet.SpanCondition.SIMPLE); + if(prefixLimit!=0) { + CharSequence prefix=second.subSequence(0, prefixLimit); + int suffixStart=set.spanBack(first, 0x7fffffff, UnicodeSet.SpanCondition.SIMPLE); + if(suffixStart==0) { + if(doNormalize) { + norm2.normalizeSecondAndAppend(first, prefix); + } else { + norm2.append(first, prefix); + } + } else { + StringBuilder middle=new StringBuilder( + first.subSequence(suffixStart, first.length())); + if(doNormalize) { + norm2.normalizeSecondAndAppend(middle, prefix); + } else { + norm2.append(middle, prefix); + } + first.delete(suffixStart, 0x7fffffff).append(middle); + } + } + if(prefixLimit<second.length()) { + CharSequence rest=second.subSequence(prefixLimit, second.length()); + if(doNormalize) { + normalize(rest, first, UnicodeSet.SpanCondition.NOT_CONTAINED); + } else { + first.append(rest); + } + } + return first; + } + + private Normalizer2 norm2; + private UnicodeSet set; +}; diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/ICUBinary.java b/jdk/src/java.base/share/classes/sun/text/normalizer/ICUBinary.java index 3e0c348a163..9ba029c5d41 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/ICUBinary.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/ICUBinary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * 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,25 +25,38 @@ /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. ******************************************************************************* */ package sun.text.normalizer; -import java.io.InputStream; +import java.io.BufferedInputStream; import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.file.FileSystems; import java.util.Arrays; +import java.security.AccessController; +import java.security.PrivilegedAction; + +public final class ICUBinary { + + private static final class IsAcceptable implements Authenticate { + // @Override when we switch to Java 6 + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == 1; + } + } -public final class ICUBinary -{ // public inner interface ------------------------------------------------ /** @@ -63,53 +76,44 @@ public final class ICUBinary // public methods -------------------------------------------------------- /** - * <p>ICU data header reader method. - * Takes a ICU generated big-endian input stream, parse the ICU standard - * file header and authenticates them. - * <p>Header format: - * <ul> - * <li> Header size (char) - * <li> Magic number 1 (byte) - * <li> Magic number 2 (byte) - * <li> Rest of the header size (char) - * <li> Reserved word (char) - * <li> Big endian indicator (byte) - * <li> Character set family indicator (byte) - * <li> Size of a char (byte) for c++ and c use - * <li> Reserved byte (byte) - * <li> Data format identifier (4 bytes), each ICU data has its own - * identifier to distinguish them. [0] major [1] minor - * [2] milli [3] micro - * <li> Data version (4 bytes), the change version of the ICU data - * [0] major [1] minor [2] milli [3] micro - * <li> Unicode version (4 bytes) this ICU is based on. - * </ul> - * - * <p> - * Example of use:<br> - * <pre> - * try { - * FileInputStream input = new FileInputStream(filename); - * If (Utility.readICUDataHeader(input, dataformat, dataversion, - * unicode) { - * System.out.println("Verified file header, this is a ICU data file"); - * } - * } catch (IOException e) { - * System.out.println("This is not a ICU data file"); - * } - * </pre> - * - * @param inputStream input stream that contains the ICU data header - * @param dataFormatIDExpected Data format expected. An array of 4 bytes - * information about the data format. - * E.g. data format ID 1.2.3.4. will became an array of - * {1, 2, 3, 4} - * @param authenticate user defined extra data authentication. This value - * can be null, if no extra authentication is needed. - * @exception IOException thrown if there is a read error or - * when header authentication fails. - * @draft 2.1 - */ + * Loads an ICU binary data file and returns it as a ByteBuffer. + * The buffer contents is normally read-only, but its position etc. can be modified. + * + * @param itemPath Relative ICU data item path, for example "root.res" or "coll/ucadata.icu". + * @return The data as a read-only ByteBuffer. + */ + public static ByteBuffer getRequiredData(String itemPath) { + final Class<ICUBinary> root = ICUBinary.class; + + try (InputStream is = AccessController.doPrivileged(new PrivilegedAction<InputStream>() { + public InputStream run() { + return root.getResourceAsStream(itemPath); + } + })) { + + BufferedInputStream b=new BufferedInputStream(is, 4096 /* data buffer size */); + DataInputStream inputStream = new DataInputStream(b); + byte[] bb = new byte[120000]; + int n = inputStream.read(bb); + ByteBuffer bytes = ByteBuffer.wrap(bb, 0, n); + return bytes; + } + catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Same as readHeader(), but returns a VersionInfo rather than a compact int. + */ + public static VersionInfo readHeaderAndDataVersion(ByteBuffer bytes, + int dataFormat, + Authenticate authenticate) + throws IOException { + return getVersionInfoFromCompactInt(readHeader(bytes, dataFormat, authenticate)); + } + + private static final byte BIG_ENDIAN_ = 1; public static final byte[] readHeader(InputStream inputStream, byte dataFormatIDExpected[], Authenticate authenticate) @@ -164,6 +168,80 @@ public final class ICUBinary return unicodeVersion; } + /** + * Reads an ICU data header, checks the data format, and returns the data version. + * + * <p>Assumes that the ByteBuffer position is 0 on input. + * The buffer byte order is set according to the data. + * The buffer position is advanced past the header (including UDataInfo and comment). + * + * <p>See C++ ucmndata.h and unicode/udata.h. + * + * @return dataVersion + * @throws IOException if this is not a valid ICU data item of the expected dataFormat + */ + public static int readHeader(ByteBuffer bytes, int dataFormat, Authenticate authenticate) + throws IOException { + assert bytes.position() == 0; + byte magic1 = bytes.get(2); + byte magic2 = bytes.get(3); + if (magic1 != MAGIC1 || magic2 != MAGIC2) { + throw new IOException(MAGIC_NUMBER_AUTHENTICATION_FAILED_); + } + + byte isBigEndian = bytes.get(8); + byte charsetFamily = bytes.get(9); + byte sizeofUChar = bytes.get(10); + if (isBigEndian < 0 || 1 < isBigEndian || + charsetFamily != CHAR_SET_ || sizeofUChar != CHAR_SIZE_) { + throw new IOException(HEADER_AUTHENTICATION_FAILED_); + } + bytes.order(isBigEndian != 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); + + int headerSize = bytes.getChar(0); + int sizeofUDataInfo = bytes.getChar(4); + if (sizeofUDataInfo < 20 || headerSize < (sizeofUDataInfo + 4)) { + throw new IOException("Internal Error: Header size error"); + } + // TODO: Change Authenticate to take int major, int minor, int milli, int micro + // to avoid array allocation. + byte[] formatVersion = new byte[] { + bytes.get(16), bytes.get(17), bytes.get(18), bytes.get(19) + }; + if (bytes.get(12) != (byte)(dataFormat >> 24) || + bytes.get(13) != (byte)(dataFormat >> 16) || + bytes.get(14) != (byte)(dataFormat >> 8) || + bytes.get(15) != (byte)dataFormat || + (authenticate != null && !authenticate.isDataVersionAcceptable(formatVersion))) { + throw new IOException(HEADER_AUTHENTICATION_FAILED_ + + String.format("; data format %02x%02x%02x%02x, format version %d.%d.%d.%d", + bytes.get(12), bytes.get(13), bytes.get(14), bytes.get(15), + formatVersion[0] & 0xff, formatVersion[1] & 0xff, + formatVersion[2] & 0xff, formatVersion[3] & 0xff)); + } + + bytes.position(headerSize); + return // dataVersion + ((int)bytes.get(20) << 24) | + ((bytes.get(21) & 0xff) << 16) | + ((bytes.get(22) & 0xff) << 8) | + (bytes.get(23) & 0xff); + } + + public static void skipBytes(ByteBuffer bytes, int skipLength) { + if (skipLength > 0) { + bytes.position(bytes.position() + skipLength); + } + } + + /** + * Returns a VersionInfo for the bytes in the compact version integer. + */ + public static VersionInfo getVersionInfoFromCompactInt(int version) { + return VersionInfo.getInstance( + version >>> 24, (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); + } + // private variables ------------------------------------------------- /** @@ -175,7 +253,6 @@ public final class ICUBinary /** * File format authentication values */ - private static final byte BIG_ENDIAN_ = 1; private static final byte CHAR_SET_ = 0; private static final byte CHAR_SIZE_ = 2; @@ -183,7 +260,7 @@ public final class ICUBinary * Error messages */ private static final String MAGIC_NUMBER_AUTHENTICATION_FAILED_ = - "ICU data file error: Not an ICU data file"; + "ICUBinary data file error: Magin number authentication failed"; private static final String HEADER_AUTHENTICATION_FAILED_ = - "ICU data file error: Header authentication failed, please check if you have a valid ICU data file"; + "ICUBinary data file error: Header authentication failed"; } diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/ICUData.java b/jdk/src/java.base/share/classes/sun/text/normalizer/ICUData.java deleted file mode 100644 index 20c21a583d6..00000000000 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/ICUData.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. - * 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. 1996-2005 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ - -package sun.text.normalizer; - -import java.io.InputStream; -import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.MissingResourceException; - -/** - * Provides access to ICU data files as InputStreams. Implements security checking. - */ -public final class ICUData { - - private static InputStream getStream(final Class<ICUData> root, final String resourceName, boolean required) { - InputStream i = null; - - if (System.getSecurityManager() != null) { - i = AccessController.doPrivileged(new PrivilegedAction<InputStream>() { - public InputStream run() { - return root.getResourceAsStream(resourceName); - } - }); - } else { - i = root.getResourceAsStream(resourceName); - } - - if (i == null && required) { - throw new MissingResourceException("could not locate data", root.getPackage().getName(), resourceName); - } - return i; - } - - /* - * Convenience override that calls getStream(ICUData.class, resourceName, false); - */ - public static InputStream getStream(String resourceName) { - return getStream(ICUData.class, resourceName, false); - } - - /* - * Convenience method that calls getStream(ICUData.class, resourceName, true). - */ - public static InputStream getRequiredStream(String resourceName) { - return getStream(ICUData.class, resourceName, true); - } -} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/IntTrie.java b/jdk/src/java.base/share/classes/sun/text/normalizer/IntTrie.java deleted file mode 100644 index 4be2d6e5862..00000000000 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/IntTrie.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. - * 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. 1996-2005 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ - -package sun.text.normalizer; - -import java.io.InputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.util.Arrays; - -/** - * Trie implementation which stores data in int, 32 bits. - * @author synwee - * @see com.ibm.icu.impl.Trie - * @since release 2.1, Jan 01 2002 - */ -public class IntTrie extends Trie -{ - // public constructors --------------------------------------------- - - /** - * <p>Creates a new Trie with the settings for the trie data.</p> - * <p>Unserialize the 32-bit-aligned input stream and use the data for the - * trie.</p> - * @param inputStream file input stream to a ICU data file, containing - * the trie - * @param datamanipulate object which provides methods to parse the char - * data - * @throws IOException thrown when data reading fails - * @draft 2.1 - */ - public IntTrie(InputStream inputStream, DataManipulate datamanipulate) - throws IOException - { - super(inputStream, datamanipulate); - if (!isIntTrie()) { - throw new IllegalArgumentException( - "Data given does not belong to a int trie."); - } - } - - // public methods -------------------------------------------------- - - /** - * Gets the value associated with the codepoint. - * If no value is associated with the codepoint, a default value will be - * returned. - * @param ch codepoint - * @return offset to data - * @draft 2.1 - */ - public final int getCodePointValue(int ch) - { - int offset = getCodePointOffset(ch); - return (offset >= 0) ? m_data_[offset] : m_initialValue_; - } - - /** - * Gets the value to the data which this lead surrogate character points - * to. - * Returned data may contain folding offset information for the next - * trailing surrogate character. - * This method does not guarantee correct results for trail surrogates. - * @param ch lead surrogate character - * @return data value - * @draft 2.1 - */ - public final int getLeadValue(char ch) - { - return m_data_[getLeadOffset(ch)]; - } - - /** - * Get a value from a folding offset (from the value of a lead surrogate) - * and a trail surrogate. - * @param leadvalue the value of a lead surrogate that contains the - * folding offset - * @param trail surrogate - * @return trie data value associated with the trail character - * @draft 2.1 - */ - public final int getTrailValue(int leadvalue, char trail) - { - if (m_dataManipulate_ == null) { - throw new NullPointerException( - "The field DataManipulate in this Trie is null"); - } - int offset = m_dataManipulate_.getFoldingOffset(leadvalue); - if (offset > 0) { - return m_data_[getRawOffset(offset, - (char)(trail & SURROGATE_MASK_))]; - } - return m_initialValue_; - } - - // protected methods ----------------------------------------------- - - /** - * <p>Parses the input stream and stores its trie content into a index and - * data array</p> - * @param inputStream data input stream containing trie data - * @exception IOException thrown when data reading fails - */ - protected final void unserialize(InputStream inputStream) - throws IOException - { - super.unserialize(inputStream); - // one used for initial value - m_data_ = new int[m_dataLength_]; - DataInputStream input = new DataInputStream(inputStream); - for (int i = 0; i < m_dataLength_; i ++) { - m_data_[i] = input.readInt(); - } - m_initialValue_ = m_data_[0]; - } - - /** - * Gets the offset to the data which the surrogate pair points to. - * @param lead lead surrogate - * @param trail trailing surrogate - * @return offset to data - * @draft 2.1 - */ - protected final int getSurrogateOffset(char lead, char trail) - { - if (m_dataManipulate_ == null) { - throw new NullPointerException( - "The field DataManipulate in this Trie is null"); - } - // get fold position for the next trail surrogate - int offset = m_dataManipulate_.getFoldingOffset(getLeadValue(lead)); - - // get the real data from the folded lead/trail units - if (offset > 0) { - return getRawOffset(offset, (char)(trail & SURROGATE_MASK_)); - } - - // return -1 if there is an error, in this case we return the default - // value: m_initialValue_ - return -1; - } - - /** - * Gets the value at the argument index. - * For use internally in TrieIterator - * @param index value at index will be retrieved - * @return 32 bit value - * @see com.ibm.icu.impl.TrieIterator - * @draft 2.1 - */ - protected final int getValue(int index) - { - return m_data_[index]; - } - - /** - * Gets the default initial value - * @return 32 bit value - * @draft 2.1 - */ - protected final int getInitialValue() - { - return m_initialValue_; - } - - // package private methods ----------------------------------------- - - /** - * Internal constructor for builder use - * @param index the index array to be slotted into this trie - * @param data the data array to be slotted into this trie - * @param initialvalue the initial value for this trie - * @param options trie options to use - * @param datamanipulate folding implementation - */ - IntTrie(char index[], int data[], int initialvalue, int options, - DataManipulate datamanipulate) - { - super(index, options, datamanipulate); - m_data_ = data; - m_dataLength_ = m_data_.length; - m_initialValue_ = initialvalue; - } - - // private data members -------------------------------------------- - - /** - * Default value - */ - private int m_initialValue_; - /** - * Array of char data - */ - private int m_data_[]; -} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/Norm2AllModes.java b/jdk/src/java.base/share/classes/sun/text/normalizer/Norm2AllModes.java new file mode 100644 index 00000000000..ecf98bf5691 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/Norm2AllModes.java @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ + +package sun.text.normalizer; + +import java.io.IOException; + +final class Norm2AllModes { + // Public API dispatch via Normalizer2 subclasses -------------------------- *** + + // Normalizer2 implementation for the old UNORM_NONE. + public static final class NoopNormalizer2 extends Normalizer2 { + @Override + public StringBuilder normalize(CharSequence src, StringBuilder dest) { + if(dest!=src) { + dest.setLength(0); + return dest.append(src); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public Appendable normalize(CharSequence src, Appendable dest) { + if(dest!=src) { + try { + return dest.append(src); + } catch(IOException e) { + throw new InternalError(e.toString(), e); + } + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { + if(first!=second) { + return first.append(second); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public StringBuilder append(StringBuilder first, CharSequence second) { + if(first!=second) { + return first.append(second); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public String getDecomposition(int c) { + return null; + } + + // No need to override the default getRawDecomposition(). + @Override + public boolean isNormalized(CharSequence s) { return true; } + + @Override + public int spanQuickCheckYes(CharSequence s) { return s.length(); } + + @Override + public boolean hasBoundaryBefore(int c) { return true; } + } + + // Intermediate class: + // Has NormalizerImpl and does boilerplate argument checking and setup. + public static abstract class Normalizer2WithImpl extends Normalizer2 { + public Normalizer2WithImpl(NormalizerImpl ni) { + impl=ni; + } + + // normalize + @Override + public StringBuilder normalize(CharSequence src, StringBuilder dest) { + if(dest==src) { + throw new IllegalArgumentException(); + } + dest.setLength(0); + normalize(src, new NormalizerImpl.ReorderingBuffer(impl, dest, src.length())); + return dest; + } + + @Override + public Appendable normalize(CharSequence src, Appendable dest) { + if(dest==src) { + throw new IllegalArgumentException(); + } + NormalizerImpl.ReorderingBuffer buffer= + new NormalizerImpl.ReorderingBuffer(impl, dest, src.length()); + normalize(src, buffer); + buffer.flush(); + return dest; + } + + protected abstract void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer); + + // normalize and append + @Override + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, true); + } + + @Override + public StringBuilder append(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, false); + } + + public StringBuilder normalizeSecondAndAppend( + StringBuilder first, CharSequence second, boolean doNormalize) { + if(first==second) { + throw new IllegalArgumentException(); + } + normalizeAndAppend( + second, doNormalize, + new NormalizerImpl.ReorderingBuffer(impl, first, first.length()+second.length())); + return first; + } + + protected abstract void normalizeAndAppend( + CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer); + + @Override + public String getDecomposition(int c) { + return impl.getDecomposition(c); + } + + @Override + public int getCombiningClass(int c) { + return impl.getCC(impl.getNorm16(c)); + } + + // quick checks + @Override + public boolean isNormalized(CharSequence s) { + return s.length()==spanQuickCheckYes(s); + } + + public final NormalizerImpl impl; + } + + public static final class DecomposeNormalizer2 extends Normalizer2WithImpl { + public DecomposeNormalizer2(NormalizerImpl ni) { + super(ni); + } + + @Override + protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { + impl.decompose(src, 0, src.length(), buffer); + } + + @Override + protected void normalizeAndAppend( + CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer) { + impl.decomposeAndAppend(src, doNormalize, buffer); + } + + @Override + public int spanQuickCheckYes(CharSequence s) { + return impl.decompose(s, 0, s.length(), null); + } + + @Override + public boolean hasBoundaryBefore(int c) { return impl.hasDecompBoundary(c, true); } + } + + public static final class ComposeNormalizer2 extends Normalizer2WithImpl { + public ComposeNormalizer2(NormalizerImpl ni, boolean fcc) { + super(ni); + onlyContiguous=fcc; + } + + @Override + protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { + impl.compose(src, 0, src.length(), onlyContiguous, true, buffer); + } + + @Override + protected void normalizeAndAppend( + CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer) { + impl.composeAndAppend(src, doNormalize, onlyContiguous, buffer); + } + + @Override + public boolean isNormalized(CharSequence s) { + // 5: small destCapacity for substring normalization + return impl.compose(s, 0, s.length(), + onlyContiguous, false, + new NormalizerImpl.ReorderingBuffer(impl, new StringBuilder(), 5)); + } + + @Override + public int spanQuickCheckYes(CharSequence s) { + return impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, true)>>>1; + } + + @Override + public boolean hasBoundaryBefore(int c) { return impl.hasCompBoundaryBefore(c); } + + private final boolean onlyContiguous; + } + + // instance cache ---------------------------------------------------------- *** + + private Norm2AllModes(NormalizerImpl ni) { + impl=ni; + comp=new ComposeNormalizer2(ni, false); + decomp=new DecomposeNormalizer2(ni); + } + + public final NormalizerImpl impl; + public final ComposeNormalizer2 comp; + public final DecomposeNormalizer2 decomp; + + private static Norm2AllModes getInstanceFromSingleton(Norm2AllModesSingleton singleton) { + if(singleton.exception!=null) { + throw singleton.exception; + } + return singleton.allModes; + } + + public static Norm2AllModes getNFCInstance() { + return getInstanceFromSingleton(NFCSingleton.INSTANCE); + } + + public static Norm2AllModes getNFKCInstance() { + return getInstanceFromSingleton(NFKCSingleton.INSTANCE); + } + + public static final NoopNormalizer2 NOOP_NORMALIZER2=new NoopNormalizer2(); + + private static final class Norm2AllModesSingleton { + private Norm2AllModesSingleton(String name) { + try { + String DATA_FILE_NAME = "/sun/text/resources/" + name + ".icu"; + NormalizerImpl impl=new NormalizerImpl().load(DATA_FILE_NAME); + allModes=new Norm2AllModes(impl); + } catch (RuntimeException e) { + exception=e; + } + } + + private Norm2AllModes allModes; + private RuntimeException exception; + } + + private static final class NFCSingleton { + private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfc"); + } + + private static final class NFKCSingleton { + private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfkc"); + } +} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/Normalizer2.java b/jdk/src/java.base/share/classes/sun/text/normalizer/Normalizer2.java new file mode 100644 index 00000000000..f2f31d73d19 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/Normalizer2.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ + +package sun.text.normalizer; + +/** + * Unicode normalization functionality for standard Unicode normalization or + * for using custom mapping tables. + * All instances of this class are unmodifiable/immutable. + * The Normalizer2 class is not intended for public subclassing. + * <p> + * The primary functions are to produce a normalized string and to detect whether + * a string is already normalized. + * The most commonly used normalization forms are those defined in + * http://www.unicode.org/unicode/reports/tr15/ + * However, this API supports additional normalization forms for specialized purposes. + * For example, NFKC_Casefold is provided via getInstance("nfkc_cf", COMPOSE) + * and can be used in implementations of UTS #46. + * <p> + * Not only are the standard compose and decompose modes supplied, + * but additional modes are provided as documented in the Mode enum. + * <p> + * Some of the functions in this class identify normalization boundaries. + * At a normalization boundary, the portions of the string + * before it and starting from it do not interact and can be handled independently. + * <p> + * The spanQuickCheckYes() stops at a normalization boundary. + * When the goal is a normalized string, then the text before the boundary + * can be copied, and the remainder can be processed with normalizeSecondAndAppend(). + * <p> + * The hasBoundaryBefore(), hasBoundaryAfter() and isInert() functions test whether + * a character is guaranteed to be at a normalization boundary, + * regardless of context. + * This is used for moving from one normalization boundary to the next + * or preceding boundary, and for performing iterative normalization. + * <p> + * Iterative normalization is useful when only a small portion of a + * longer string needs to be processed. + * For example, in ICU, iterative normalization is used by the NormalizationTransliterator + * (to avoid replacing already-normalized text) and ucol_nextSortKeyPart() + * (to process only the substring for which sort key bytes are computed). + * <p> + * The set of normalization boundaries returned by these functions may not be + * complete: There may be more boundaries that could be returned. + * Different functions may return different boundaries. + * @stable ICU 4.4 + * @author Markus W. Scherer + */ +abstract class Normalizer2 { + + /** + * Returns a Normalizer2 instance for Unicode NFC normalization. + * Same as getInstance(null, "nfc", Mode.COMPOSE). + * Returns an unmodifiable singleton instance. + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFCInstance() { + return Norm2AllModes.getNFCInstance().comp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFD normalization. + * Same as getInstance(null, "nfc", Mode.DECOMPOSE). + * Returns an unmodifiable singleton instance. + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFDInstance() { + return Norm2AllModes.getNFCInstance().decomp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFKC normalization. + * Same as getInstance(null, "nfkc", Mode.COMPOSE). + * Returns an unmodifiable singleton instance. + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFKCInstance() { + return Norm2AllModes.getNFKCInstance().comp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFKD normalization. + * Same as getInstance(null, "nfkc", Mode.DECOMPOSE). + * Returns an unmodifiable singleton instance. + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFKDInstance() { + return Norm2AllModes.getNFKCInstance().decomp; + } + + /** + * Returns the normalized form of the source string. + * @param src source string + * @return normalized src + * @stable ICU 4.4 + */ + public String normalize(CharSequence src) { + if(src instanceof String) { + // Fastpath: Do not construct a new String if the src is a String + // and is already normalized. + int spanLength=spanQuickCheckYes(src); + if(spanLength==src.length()) { + return (String)src; + } + StringBuilder sb=new StringBuilder(src.length()).append(src, 0, spanLength); + return normalizeSecondAndAppend(sb, src.subSequence(spanLength, src.length())).toString(); + } + return normalize(src, new StringBuilder(src.length())).toString(); + } + + /** + * Writes the normalized form of the source string to the destination string + * (replacing its contents) and returns the destination string. + * The source and destination strings must be different objects. + * @param src source string + * @param dest destination string; its contents is replaced with normalized src + * @return dest + * @stable ICU 4.4 + */ + public abstract StringBuilder normalize(CharSequence src, StringBuilder dest); + + /** + * Writes the normalized form of the source string to the destination Appendable + * and returns the destination Appendable. + * The source and destination strings must be different objects. + * + * <p>Any {@link java.io.IOException} is wrapped into a {@link com.ibm.icu.util.ICUUncheckedIOException}. + * + * @param src source string + * @param dest destination Appendable; gets normalized src appended + * @return dest + * @stable ICU 4.6 + */ + public abstract Appendable normalize(CharSequence src, Appendable dest); + + /** + * Appends the normalized form of the second string to the first string + * (merging them at the boundary) and returns the first string. + * The result is normalized if the first string was normalized. + * The first and second strings must be different objects. + * @param first string, should be normalized + * @param second string, will be normalized + * @return first + * @stable ICU 4.4 + */ + public abstract StringBuilder normalizeSecondAndAppend( + StringBuilder first, CharSequence second); + + /** + * Appends the second string to the first string + * (merging them at the boundary) and returns the first string. + * The result is normalized if both the strings were normalized. + * The first and second strings must be different objects. + * @param first string, should be normalized + * @param second string, should be normalized + * @return first + * @stable ICU 4.4 + */ + public abstract StringBuilder append(StringBuilder first, CharSequence second); + + /** + * Gets the decomposition mapping of c. + * Roughly equivalent to normalizing the String form of c + * on a DECOMPOSE Normalizer2 instance, but much faster, and except that this function + * returns null if c does not have a decomposition mapping in this instance's data. + * This function is independent of the mode of the Normalizer2. + * @param c code point + * @return c's decomposition mapping, if any; otherwise null + * @stable ICU 4.6 + */ + public abstract String getDecomposition(int c); + + /** + * Gets the combining class of c. + * The default implementation returns 0 + * but all standard implementations return the Unicode Canonical_Combining_Class value. + * @param c code point + * @return c's combining class + * @stable ICU 49 + */ + public int getCombiningClass(int c) { return 0; } + + /** + * Tests if the string is normalized. + * Internally, in cases where the quickCheck() method would return "maybe" + * (which is only possible for the two COMPOSE modes) this method + * resolves to "yes" or "no" to provide a definitive result, + * at the cost of doing more work in those cases. + * @param s input string + * @return true if s is normalized + * @stable ICU 4.4 + */ + public abstract boolean isNormalized(CharSequence s); + + /** + * Returns the end of the normalized substring of the input string. + * In other words, with <code>end=spanQuickCheckYes(s);</code> + * the substring <code>s.subSequence(0, end)</code> + * will pass the quick check with a "yes" result. + * <p> + * The returned end index is usually one or more characters before the + * "no" or "maybe" character: The end index is at a normalization boundary. + * (See the class documentation for more about normalization boundaries.) + * <p> + * When the goal is a normalized string and most input strings are expected + * to be normalized already, then call this method, + * and if it returns a prefix shorter than the input string, + * copy that prefix and use normalizeSecondAndAppend() for the remainder. + * @param s input string + * @return "yes" span end index + * @stable ICU 4.4 + */ + public abstract int spanQuickCheckYes(CharSequence s); + + /** + * Tests if the character always has a normalization boundary before it, + * regardless of context. + * If true, then the character does not normalization-interact with + * preceding characters. + * In other words, a string containing this character can be normalized + * by processing portions before this character and starting from this + * character independently. + * This is used for iterative normalization. See the class documentation for details. + * @param c character to test + * @return true if c has a normalization boundary before it + * @stable ICU 4.4 + */ + public abstract boolean hasBoundaryBefore(int c); + + /** + * Sole constructor. (For invocation by subclass constructors, + * typically implicit.) + * @internal + * deprecated This API is ICU internal only. + */ + protected Normalizer2() { + } +} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerBase.java b/jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerBase.java index 43c4e10167c..23a66dcaa05 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerBase.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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,18 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * + * Copyright (C) 2000-2014, International Business Machines Corporation and + * others. All Rights Reserved. ******************************************************************************* */ - package sun.text.normalizer; import java.text.CharacterIterator; @@ -125,8 +120,8 @@ import java.text.Normalizer; * * normalize(FCD) may be implemented with NFD. * - * For more details on FCD see the collation design document: - * http://source.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm + * For more details on FCD see Unicode Technical Note #5 (Canonical Equivalence in Applications): + * http://www.unicode.org/notes/tn5/#FCD * * ICU collation performs either NFD or FCD normalization automatically if * normalization is turned on for the collator object. Beyond collation and @@ -138,26 +133,88 @@ import java.text.Normalizer; * often do not encode any combining marks by themselves. For conversion to such * character encodings the Unicode text needs to be normalized to NFC. * For more usage examples, see the Unicode Standard Annex. + * + * Note: The Normalizer class also provides API for iterative normalization. + * While the setIndex() and getIndex() refer to indices in the + * underlying Unicode input text, the next() and previous() methods + * iterate through characters in the normalized output. + * This means that there is not necessarily a one-to-one correspondence + * between characters returned by next() and previous() and the indices + * passed to and returned from setIndex() and getIndex(). + * It is for this reason that Normalizer does not implement the CharacterIterator interface. + * * @stable ICU 2.8 */ - +// Original filename in ICU4J: Normalizer.java public final class NormalizerBase implements Cloneable { - //------------------------------------------------------------------------- - // Private data - //------------------------------------------------------------------------- - private char[] buffer = new char[100]; - private int bufferStart = 0; - private int bufferPos = 0; - private int bufferLimit = 0; - // The input text and our position in it private UCharacterIterator text; - private Mode mode = NFC; - private int options = 0; + private Normalizer2 norm2; + private Mode mode; + private int options; + + // The normalization buffer is the result of normalization + // of the source in [currentIndex..nextIndex] . private int currentIndex; private int nextIndex; + // A buffer for holding intermediate results + private StringBuilder buffer; + private int bufferPos; + + // Helper classes to defer loading of normalization data. + private static final class ModeImpl { + private ModeImpl(Normalizer2 n2) { + normalizer2 = n2; + } + private final Normalizer2 normalizer2; + } + + private static final class NFDModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFDInstance()); + } + + private static final class NFKDModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFKDInstance()); + } + + private static final class NFCModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFCInstance()); + } + + private static final class NFKCModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFKCInstance()); + } + + private static final class Unicode32 { + private static final UnicodeSet INSTANCE = new UnicodeSet("[:age=3.2:]").freeze(); + } + + private static final class NFD32ModeImpl { + private static final ModeImpl INSTANCE = + new ModeImpl(new FilteredNormalizer2(Normalizer2.getNFDInstance(), + Unicode32.INSTANCE)); + } + + private static final class NFKD32ModeImpl { + private static final ModeImpl INSTANCE = + new ModeImpl(new FilteredNormalizer2(Normalizer2.getNFKDInstance(), + Unicode32.INSTANCE)); + } + + private static final class NFC32ModeImpl { + private static final ModeImpl INSTANCE = + new ModeImpl(new FilteredNormalizer2(Normalizer2.getNFCInstance(), + Unicode32.INSTANCE)); + } + + private static final class NFKC32ModeImpl { + private static final ModeImpl INSTANCE = + new ModeImpl(new FilteredNormalizer2(Normalizer2.getNFKCInstance(), + Unicode32.INSTANCE)); + } + /** * Options bit set value to select Unicode 3.2 normalization * (except NormalizationCorrections). @@ -166,6 +223,17 @@ public final class NormalizerBase implements Cloneable { */ public static final int UNICODE_3_2=0x20; + public static final int UNICODE_3_2_0_ORIGINAL=UNICODE_3_2; + + /* + * Default option for the latest Unicode normalization. This option is + * provided mainly for testing. + * The value zero means that normalization is done with the fixes for + * - Corrigendum 4 (Five CJK Canonical Mapping Errors) + * - Corrigendum 5 (Normalization Idempotency) + */ + public static final int UNICODE_LATEST = 0x00; + /** * Constant indicating that the end of the iteration has been reached. * This is guaranteed to have the same value as {@link UCharacterIterator#DONE}. @@ -175,101 +243,80 @@ public final class NormalizerBase implements Cloneable { /** * Constants for normalization modes. + * <p> + * The Mode class is not intended for public subclassing. + * Only the Mode constants provided by the Normalizer class should be used, + * and any fields or methods should not be called or overridden by users. * @stable ICU 2.8 */ - public static class Mode { - private int modeValue; - private Mode(int value) { - modeValue = value; + public static abstract class Mode { + + /** + * Sole constructor + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected Mode() { } /** - * This method is used for method dispatch - * @stable ICU 2.6 + * @internal + * @deprecated This API is ICU internal only. */ - protected int normalize(char[] src, int srcStart, int srcLimit, - char[] dest,int destStart,int destLimit, - UnicodeSet nx) { - int srcLen = (srcLimit - srcStart); - int destLen = (destLimit - destStart); - if( srcLen > destLen ) { - return srcLen; - } - System.arraycopy(src,srcStart,dest,destStart,srcLen); - return srcLen; + @Deprecated + protected abstract Normalizer2 getNormalizer2(int options); + } + + private static Mode toMode(Normalizer.Form form) { + switch (form) { + case NFC : + return NFC; + case NFD : + return NFD; + case NFKC : + return NFKC; + case NFKD : + return NFKD; } - /** - * This method is used for method dispatch - * @stable ICU 2.6 - */ - protected int normalize(char[] src, int srcStart, int srcLimit, - char[] dest,int destStart,int destLimit, - int options) { - return normalize( src, srcStart, srcLimit, - dest,destStart,destLimit, - NormalizerImpl.getNX(options) - ); - } + throw new IllegalArgumentException("Unexpected normalization form: " + + form); + } - /** - * This method is used for method dispatch - * @stable ICU 2.6 - */ - protected String normalize(String src, int options) { - return src; - } + private static final class NONEMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { return Norm2AllModes.NOOP_NORMALIZER2; } + } - /** - * This method is used for method dispatch - * @stable ICU 2.8 - */ - protected int getMinC() { - return -1; + private static final class NFDMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options&UNICODE_3_2) != 0 ? + NFD32ModeImpl.INSTANCE.normalizer2 : + NFDModeImpl.INSTANCE.normalizer2; } + } - /** - * This method is used for method dispatch - * @stable ICU 2.8 - */ - protected int getMask() { - return -1; + private static final class NFKDMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options&UNICODE_3_2) != 0 ? + NFKD32ModeImpl.INSTANCE.normalizer2 : + NFKDModeImpl.INSTANCE.normalizer2; } + } - /** - * This method is used for method dispatch - * @stable ICU 2.8 - */ - protected IsPrevBoundary getPrevBoundary() { - return null; + private static final class NFCMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options&UNICODE_3_2) != 0 ? + NFC32ModeImpl.INSTANCE.normalizer2 : + NFCModeImpl.INSTANCE.normalizer2; } + } - /** - * This method is used for method dispatch - * @stable ICU 2.8 - */ - protected IsNextBoundary getNextBoundary() { - return null; - } - - /** - * This method is used for method dispatch - * @stable ICU 2.6 - */ - protected QuickCheckResult quickCheck(char[] src,int start, int limit, - boolean allowMaybe,UnicodeSet nx) { - if(allowMaybe) { - return MAYBE; - } - return NO; - } - - /** - * This method is used for method dispatch - * @stable ICU 2.8 - */ - protected boolean isNFSkippable(int c) { - return true; + private static final class NFKCMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options&UNICODE_3_2) != 0 ? + NFKC32ModeImpl.INSTANCE.normalizer2 : + NFKCModeImpl.INSTANCE.normalizer2; } } @@ -277,290 +324,39 @@ public final class NormalizerBase implements Cloneable { * No decomposition/composition. * @stable ICU 2.8 */ - public static final Mode NONE = new Mode(1); + public static final Mode NONE = new NONEMode(); /** * Canonical decomposition. * @stable ICU 2.8 */ - public static final Mode NFD = new NFDMode(2); - - private static final class NFDMode extends Mode { - private NFDMode(int value) { - super(value); - } - - protected int normalize(char[] src, int srcStart, int srcLimit, - char[] dest,int destStart,int destLimit, - UnicodeSet nx) { - int[] trailCC = new int[1]; - return NormalizerImpl.decompose(src, srcStart,srcLimit, - dest, destStart,destLimit, - false, trailCC,nx); - } - - protected String normalize( String src, int options) { - return decompose(src,false,options); - } - - protected int getMinC() { - return NormalizerImpl.MIN_WITH_LEAD_CC; - } - - protected IsPrevBoundary getPrevBoundary() { - return new IsPrevNFDSafe(); - } - - protected IsNextBoundary getNextBoundary() { - return new IsNextNFDSafe(); - } - - protected int getMask() { - return (NormalizerImpl.CC_MASK|NormalizerImpl.QC_NFD); - } - - protected QuickCheckResult quickCheck(char[] src,int start, - int limit,boolean allowMaybe, - UnicodeSet nx) { - return NormalizerImpl.quickCheck( - src, start,limit, - NormalizerImpl.getFromIndexesArr( - NormalizerImpl.INDEX_MIN_NFD_NO_MAYBE - ), - NormalizerImpl.QC_NFD, - 0, - allowMaybe, - nx - ); - } - - protected boolean isNFSkippable(int c) { - return NormalizerImpl.isNFSkippable(c,this, - (NormalizerImpl.CC_MASK|NormalizerImpl.QC_NFD) - ); - } - } + public static final Mode NFD = new NFDMode(); /** * Compatibility decomposition. * @stable ICU 2.8 */ - public static final Mode NFKD = new NFKDMode(3); - - private static final class NFKDMode extends Mode { - private NFKDMode(int value) { - super(value); - } - - protected int normalize(char[] src, int srcStart, int srcLimit, - char[] dest,int destStart,int destLimit, - UnicodeSet nx) { - int[] trailCC = new int[1]; - return NormalizerImpl.decompose(src, srcStart,srcLimit, - dest, destStart,destLimit, - true, trailCC, nx); - } - - protected String normalize( String src, int options) { - return decompose(src,true,options); - } - - protected int getMinC() { - return NormalizerImpl.MIN_WITH_LEAD_CC; - } - - protected IsPrevBoundary getPrevBoundary() { - return new IsPrevNFDSafe(); - } - - protected IsNextBoundary getNextBoundary() { - return new IsNextNFDSafe(); - } - - protected int getMask() { - return (NormalizerImpl.CC_MASK|NormalizerImpl.QC_NFKD); - } - - protected QuickCheckResult quickCheck(char[] src,int start, - int limit,boolean allowMaybe, - UnicodeSet nx) { - return NormalizerImpl.quickCheck( - src,start,limit, - NormalizerImpl.getFromIndexesArr( - NormalizerImpl.INDEX_MIN_NFKD_NO_MAYBE - ), - NormalizerImpl.QC_NFKD, - NormalizerImpl.OPTIONS_COMPAT, - allowMaybe, - nx - ); - } - - protected boolean isNFSkippable(int c) { - return NormalizerImpl.isNFSkippable(c, this, - (NormalizerImpl.CC_MASK|NormalizerImpl.QC_NFKD) - ); - } - } + public static final Mode NFKD = new NFKDMode(); /** * Canonical decomposition followed by canonical composition. * @stable ICU 2.8 */ - public static final Mode NFC = new NFCMode(4); + public static final Mode NFC = new NFCMode(); - private static final class NFCMode extends Mode{ - private NFCMode(int value) { - super(value); - } - protected int normalize(char[] src, int srcStart, int srcLimit, - char[] dest,int destStart,int destLimit, - UnicodeSet nx) { - return NormalizerImpl.compose( src, srcStart, srcLimit, - dest,destStart,destLimit, - 0, nx); - } - - protected String normalize( String src, int options) { - return compose(src, false, options); - } - - protected int getMinC() { - return NormalizerImpl.getFromIndexesArr( - NormalizerImpl.INDEX_MIN_NFC_NO_MAYBE - ); - } - protected IsPrevBoundary getPrevBoundary() { - return new IsPrevTrueStarter(); - } - protected IsNextBoundary getNextBoundary() { - return new IsNextTrueStarter(); - } - protected int getMask() { - return (NormalizerImpl.CC_MASK|NormalizerImpl.QC_NFC); - } - protected QuickCheckResult quickCheck(char[] src,int start, - int limit,boolean allowMaybe, - UnicodeSet nx) { - return NormalizerImpl.quickCheck( - src,start,limit, - NormalizerImpl.getFromIndexesArr( - NormalizerImpl.INDEX_MIN_NFC_NO_MAYBE - ), - NormalizerImpl.QC_NFC, - 0, - allowMaybe, - nx - ); - } - protected boolean isNFSkippable(int c) { - return NormalizerImpl.isNFSkippable(c,this, - ( NormalizerImpl.CC_MASK|NormalizerImpl.COMBINES_ANY| - (NormalizerImpl.QC_NFC & NormalizerImpl.QC_ANY_NO) - ) - ); - } - }; - - /** - * Compatibility decomposition followed by canonical composition. - * @stable ICU 2.8 - */ - public static final Mode NFKC =new NFKCMode(5); - - private static final class NFKCMode extends Mode{ - private NFKCMode(int value) { - super(value); - } - protected int normalize(char[] src, int srcStart, int srcLimit, - char[] dest,int destStart,int destLimit, - UnicodeSet nx) { - return NormalizerImpl.compose(src, srcStart,srcLimit, - dest, destStart,destLimit, - NormalizerImpl.OPTIONS_COMPAT, nx); - } - - protected String normalize( String src, int options) { - return compose(src, true, options); - } - protected int getMinC() { - return NormalizerImpl.getFromIndexesArr( - NormalizerImpl.INDEX_MIN_NFKC_NO_MAYBE - ); - } - protected IsPrevBoundary getPrevBoundary() { - return new IsPrevTrueStarter(); - } - protected IsNextBoundary getNextBoundary() { - return new IsNextTrueStarter(); - } - protected int getMask() { - return (NormalizerImpl.CC_MASK|NormalizerImpl.QC_NFKC); - } - protected QuickCheckResult quickCheck(char[] src,int start, - int limit,boolean allowMaybe, - UnicodeSet nx) { - return NormalizerImpl.quickCheck( - src,start,limit, - NormalizerImpl.getFromIndexesArr( - NormalizerImpl.INDEX_MIN_NFKC_NO_MAYBE - ), - NormalizerImpl.QC_NFKC, - NormalizerImpl.OPTIONS_COMPAT, - allowMaybe, - nx - ); - } - protected boolean isNFSkippable(int c) { - return NormalizerImpl.isNFSkippable(c, this, - ( NormalizerImpl.CC_MASK|NormalizerImpl.COMBINES_ANY| - (NormalizerImpl.QC_NFKC & NormalizerImpl.QC_ANY_NO) - ) - ); - } - }; - - /** - * Result values for quickCheck(). - * For details see Unicode Technical Report 15. - * @stable ICU 2.8 - */ - public static final class QuickCheckResult{ - private int resultValue; - private QuickCheckResult(int value) { - resultValue=value; - } - } - /** - * Indicates that string is not in the normalized format - * @stable ICU 2.8 - */ - public static final QuickCheckResult NO = new QuickCheckResult(0); - - /** - * Indicates that string is in the normalized format - * @stable ICU 2.8 - */ - public static final QuickCheckResult YES = new QuickCheckResult(1); - - /** - * Indicates it cannot be determined if string is in the normalized - * format without further thorough checks. - * @stable ICU 2.8 - */ - public static final QuickCheckResult MAYBE = new QuickCheckResult(2); + public static final Mode NFKC =new NFKCMode(); //------------------------------------------------------------------------- - // Constructors + // Iterator constructors //------------------------------------------------------------------------- /** - * Creates a new {@code Normalizer} object for iterating over the + * Creates a new {@code NormalizerBase} object for iterating over the * normalized form of a given string. * <p> * The {@code options} parameter specifies which optional - * {@code Normalizer} features are to be enabled for this object. - * + * {@code NormalizerBase} features are to be enabled for this object. + * <p> * @param str The string to be normalized. The normalization * will start at the beginning of the string. * @@ -576,25 +372,19 @@ public final class NormalizerBase implements Cloneable { this.text = UCharacterIterator.getInstance(str); this.mode = mode; this.options=opt; + norm2 = mode.getNormalizer2(opt); + buffer = new StringBuilder(); } - /** - * Creates a new {@code Normalizer} object for iterating over the - * normalized form of the given text. - * - * @param iter The input text to be normalized. The normalization - * will start at the beginning of the string. - * - * @param mode The normalization mode. - */ - public NormalizerBase(CharacterIterator iter, Mode mode) { - this(iter, mode, UNICODE_LATEST); + public NormalizerBase(String str, Mode mode) { + this(str, mode, 0); } + /** - * Creates a new {@code Normalizer} object for iterating over the + * Creates a new {@code NormalizerBase} object for iterating over the * normalized form of the given text. - * + * <p> * @param iter The input text to be normalized. The normalization * will start at the beginning of the string. * @@ -607,15 +397,19 @@ public final class NormalizerBase implements Cloneable { * @stable ICU 2.6 */ public NormalizerBase(CharacterIterator iter, Mode mode, int opt) { - this.text = UCharacterIterator.getInstance( - (CharacterIterator)iter.clone() - ); + this.text = UCharacterIterator.getInstance((CharacterIterator)iter.clone()); this.mode = mode; this.options = opt; + norm2 = mode.getNormalizer2(opt); + buffer = new StringBuilder(); + } + + public NormalizerBase(CharacterIterator iter, Mode mode) { + this(iter, mode, 0); } /** - * Clones this {@code Normalizer} object. All properties of this + * Clones this {@code NormalizerBase} object. All properties of this * object are duplicated in the new object, including the cloning of any * {@link CharacterIterator} that was passed in to the constructor * or to {@link #setText(CharacterIterator) setText}. @@ -628,11 +422,13 @@ public final class NormalizerBase implements Cloneable { try { NormalizerBase copy = (NormalizerBase) super.clone(); copy.text = (UCharacterIterator) text.clone(); - //clone the internal buffer - if (buffer != null) { - copy.buffer = new char[buffer.length]; - System.arraycopy(buffer,0,copy.buffer,0,buffer.length); - } + copy.mode = mode; + copy.options = options; + copy.norm2 = norm2; + copy.buffer = new StringBuilder(buffer); + copy.bufferPos = bufferPos; + copy.currentIndex = currentIndex; + copy.nextIndex = nextIndex; return copy; } catch (CloneNotSupportedException e) { @@ -640,150 +436,60 @@ public final class NormalizerBase implements Cloneable { } } - //-------------------------------------------------------------------------- - // Static Utility methods - //-------------------------------------------------------------------------- - /** - * Compose a string. - * The string will be composed according to the specified mode. - * @param str The string to compose. - * @param compat If true the string will be composed according to - * NFKC rules and if false will be composed according to - * NFC rules. - * @param options The only recognized option is UNICODE_3_2 - * @return String The composed string + * Normalizes a {@code String} using the given normalization operation. + * <p> + * The {@code options} parameter specifies which optional + * {@code NormalizerBase} features are to be enabled for this operation. + * Currently the only available option is {@link #UNICODE_3_2}. + * If you want the default behavior corresponding to one of the standard + * Unicode Normalization Forms, use 0 for this argument. + * <p> + * @param str the input string to be normalized. + * @param mode the normalization mode + * @param options the optional features to be enabled. + * @return String the normalized string * @stable ICU 2.6 */ - public static String compose(String str, boolean compat, int options) { - - char[] dest, src; - if (options == UNICODE_3_2_0_ORIGINAL) { - String mappedStr = NormalizerImpl.convert(str); - dest = new char[mappedStr.length()*MAX_BUF_SIZE_COMPOSE]; - src = mappedStr.toCharArray(); - } else { - dest = new char[str.length()*MAX_BUF_SIZE_COMPOSE]; - src = str.toCharArray(); - } - int destSize=0; - - UnicodeSet nx = NormalizerImpl.getNX(options); - - /* reset options bits that should only be set here or inside compose() */ - options&=~(NormalizerImpl.OPTIONS_SETS_MASK|NormalizerImpl.OPTIONS_COMPAT|NormalizerImpl.OPTIONS_COMPOSE_CONTIGUOUS); - - if(compat) { - options|=NormalizerImpl.OPTIONS_COMPAT; - } - - for(;;) { - destSize=NormalizerImpl.compose(src,0,src.length, - dest,0,dest.length,options, - nx); - if(destSize<=dest.length) { - return new String(dest,0,destSize); - } else { - dest = new char[destSize]; - } - } + public static String normalize(String str, Mode mode, int options) { + return mode.getNormalizer2(options).normalize(str); } - private static final int MAX_BUF_SIZE_COMPOSE = 2; - private static final int MAX_BUF_SIZE_DECOMPOSE = 3; + public static String normalize(String str, Normalizer.Form form) { + return NormalizerBase.normalize(str, toMode(form), UNICODE_LATEST); + } - /** - * Decompose a string. - * The string will be decomposed according to the specified mode. - * @param str The string to decompose. - * @param compat If true the string will be decomposed according to NFKD - * rules and if false will be decomposed according to NFD - * rules. - * @return String The decomposed string - * @stable ICU 2.8 - */ - public static String decompose(String str, boolean compat) { - return decompose(str,compat,UNICODE_LATEST); + public static String normalize(String str, Normalizer.Form form, int options) { + return NormalizerBase.normalize(str, toMode(form), options); } /** - * Decompose a string. - * The string will be decomposed according to the specified mode. - * @param str The string to decompose. - * @param compat If true the string will be decomposed according to NFKD - * rules and if false will be decomposed according to NFD - * rules. - * @param options The normalization options, ORed together (0 for no options). - * @return String The decomposed string + * Test if a string is in a given normalization form. + * This is semantically equivalent to source.equals(normalize(source, mode)). + * + * Unlike quickCheck(), this function returns a definitive result, + * never a "maybe". + * For NFD, NFKD, and FCD, both functions work exactly the same. + * For NFC and NFKC where quickCheck may return "maybe", this function will + * perform further tests to arrive at a true/false result. + * @param str the input string to be checked to see if it is + * normalized + * @param mode the normalization mode + * @param options Options for use with exclusion set and tailored Normalization + * The only option that is currently recognized is UNICODE_3_2 + * @see #isNormalized * @stable ICU 2.6 */ - public static String decompose(String str, boolean compat, int options) { - - int[] trailCC = new int[1]; - int destSize=0; - UnicodeSet nx = NormalizerImpl.getNX(options); - char[] dest; - - if (options == UNICODE_3_2_0_ORIGINAL) { - String mappedStr = NormalizerImpl.convert(str); - dest = new char[mappedStr.length()*MAX_BUF_SIZE_DECOMPOSE]; - - for(;;) { - destSize=NormalizerImpl.decompose(mappedStr.toCharArray(),0,mappedStr.length(), - dest,0,dest.length, - compat,trailCC, nx); - if(destSize<=dest.length) { - return new String(dest,0,destSize); - } else { - dest = new char[destSize]; - } - } - } else { - dest = new char[str.length()*MAX_BUF_SIZE_DECOMPOSE]; - - for(;;) { - destSize=NormalizerImpl.decompose(str.toCharArray(),0,str.length(), - dest,0,dest.length, - compat,trailCC, nx); - if(destSize<=dest.length) { - return new String(dest,0,destSize); - } else { - dest = new char[destSize]; - } - } - } + public static boolean isNormalized(String str, Mode mode, int options) { + return mode.getNormalizer2(options).isNormalized(str); } - /** - * Normalize a string. - * The string will be normalized according to the specified normalization - * mode and options. - * @param src The char array to compose. - * @param srcStart Start index of the source - * @param srcLimit Limit index of the source - * @param dest The char buffer to fill in - * @param destStart Start index of the destination buffer - * @param destLimit End index of the destination buffer - * @param mode The normalization mode; one of Normalizer.NONE, - * Normalizer.NFD, Normalizer.NFC, Normalizer.NFKC, - * Normalizer.NFKD, Normalizer.DEFAULT - * @param options The normalization options, ORed together (0 for no options). - * @return int The total buffer size needed;if greater than length of - * result, the output was truncated. - * @exception IndexOutOfBoundsException if the target capacity is - * less than the required length - * @stable ICU 2.6 - */ - public static int normalize(char[] src,int srcStart, int srcLimit, - char[] dest,int destStart, int destLimit, - Mode mode, int options) { - int length = mode.normalize(src,srcStart,srcLimit,dest,destStart,destLimit, options); + public static boolean isNormalized(String str, Normalizer.Form form) { + return NormalizerBase.isNormalized(str, toMode(form), UNICODE_LATEST); + } - if(length<=(destLimit-destStart)) { - return length; - } else { - throw new IndexOutOfBoundsException(Integer.toString(length)); - } + public static boolean isNormalized(String str, Normalizer.Form form, int options) { + return NormalizerBase.isNormalized(str, toMode(form), options); } //------------------------------------------------------------------------- @@ -796,8 +502,8 @@ public final class NormalizerBase implements Cloneable { * @stable ICU 2.8 */ public int current() { - if(bufferPos<bufferLimit || nextNormalize()) { - return getCodePointAt(bufferPos); + if(bufferPos<buffer.length() || nextNormalize()) { + return buffer.codePointAt(bufferPos); } else { return DONE; } @@ -811,16 +517,15 @@ public final class NormalizerBase implements Cloneable { * @stable ICU 2.8 */ public int next() { - if(bufferPos<bufferLimit || nextNormalize()) { - int c=getCodePointAt(bufferPos); - bufferPos+=(c>0xFFFF) ? 2 : 1; + if(bufferPos<buffer.length() || nextNormalize()) { + int c=buffer.codePointAt(bufferPos); + bufferPos+=Character.charCount(c); return c; } else { return DONE; } } - /** * Return the previous character in the normalized text and decrement * the iteration position by one. If the beginning @@ -830,8 +535,8 @@ public final class NormalizerBase implements Cloneable { */ public int previous() { if(bufferPos>0 || previousNormalize()) { - int c=getCodePointAt(bufferPos-1); - bufferPos-=(c>0xFFFF) ? 2 : 1; + int c=buffer.codePointBefore(bufferPos); + bufferPos-=Character.charCount(c); return c; } else { return DONE; @@ -859,8 +564,8 @@ public final class NormalizerBase implements Cloneable { * @stable ICU 2.8 */ public void setIndexOnly(int index) { - text.setIndex(index); - currentIndex=nextIndex=index; // validates index + text.setIndex(index); // validates index + currentIndex=nextIndex=index; clearBuffer(); } @@ -874,7 +579,7 @@ public final class NormalizerBase implements Cloneable { * necessarily a one-to-one correspondence between characters returned * by {@code next} and {@code previous} and the indices passed to and * returned from {@code setIndex} and {@link #getIndex}. - * + * <p> * @param index the desired index in the input text. * * @return the first normalized character that is the result of iterating @@ -882,11 +587,9 @@ public final class NormalizerBase implements Cloneable { * * @throws IllegalArgumentException if the given index is less than * {@link #getBeginIndex} or greater than {@link #getEndIndex}. - * @return The codepoint as an int - * @deprecated ICU 3.2 + * deprecated ICU 3.2 * @obsolete ICU 3.2 */ - @Deprecated public int setIndex(int index) { setIndexOnly(index); return current(); @@ -895,7 +598,7 @@ public final class NormalizerBase implements Cloneable { /** * Retrieve the index of the start of the input text. This is the begin * index of the {@code CharacterIterator} or the start (i.e. 0) of the - * {@code String} over which this {@code Normalizer} is iterating + * {@code String} over which this {@code NormalizerBase} is iterating * @deprecated ICU 2.2. Use startIndex() instead. * @return The codepoint as an int * @see #startIndex @@ -908,7 +611,7 @@ public final class NormalizerBase implements Cloneable { /** * Retrieve the index of the end of the input text. This is the end index * of the {@code CharacterIterator} or the length of the {@code String} - * over which this {@code Normalizer} is iterating + * over which this {@code NormalizerBase} is iterating * @deprecated ICU 2.2. Use endIndex() instead. * @return The codepoint as an int * @see #endIndex @@ -934,7 +637,7 @@ public final class NormalizerBase implements Cloneable { * @stable ICU 2.8 */ public int getIndex() { - if(bufferPos<bufferLimit) { + if(bufferPos<buffer.length()) { return currentIndex; } else { return nextIndex; @@ -942,9 +645,9 @@ public final class NormalizerBase implements Cloneable { } /** - * Retrieve the index of the end of the input text. This is the end index + * Retrieve the index of the end of the input text. This is the end index * of the {@code CharacterIterator} or the length of the {@code String} - * over which this {@code Normalizer} is iterating + * over which this {@code NormalizerBase} is iterating * @return The current iteration position * @stable ICU 2.8 */ @@ -953,7 +656,7 @@ public final class NormalizerBase implements Cloneable { } //------------------------------------------------------------------------- - // Property access methods + // Iterator attributes //------------------------------------------------------------------------- /** * Set the normalization mode for this object. @@ -964,18 +667,18 @@ public final class NormalizerBase implements Cloneable { * until the iteration is able to re-sync at the next base character. * It is safest to call {@link #setText setText()}, {@link #first}, * {@link #last}, etc. after calling {@code setMode}. - * - * @param newMode the new mode for this {@code Normalizer}. + * <p> + * @param newMode the new mode for this {@code NormalizerBase}. * The supported modes are: * <ul> - * <li>{@link #COMPOSE} - Unicode canonical decompositiion - * followed by canonical composition. - * <li>{@link #COMPOSE_COMPAT} - Unicode compatibility decompositiion - * follwed by canonical composition. - * <li>{@link #DECOMP} - Unicode canonical decomposition - * <li>{@link #DECOMP_COMPAT} - Unicode compatibility decomposition. - * <li>{@link #NO_OP} - Do nothing but return characters - * from the underlying input text. + * <li>{@link #NFC} - Unicode canonical decompositiion + * followed by canonical composition. + * <li>{@link #NFKC} - Unicode compatibility decompositiion + * follwed by canonical composition. + * <li>{@link #NFD} - Unicode canonical decomposition + * <li>{@link #NFKD} - Unicode compatibility decomposition. + * <li>{@link #NONE} - Do nothing but return characters + * from the underlying input text. * </ul> * * @see #getMode @@ -983,9 +686,11 @@ public final class NormalizerBase implements Cloneable { */ public void setMode(Mode newMode) { mode = newMode; + norm2 = mode.getNormalizer2(options); } + /** - * Return the basic operation performed by this {@code Normalizer} + * Return the basic operation performed by this {@code NormalizerBase} * * @see #setMode * @stable ICU 2.8 @@ -995,688 +700,83 @@ public final class NormalizerBase implements Cloneable { } /** - * Set the input text over which this {@code Normalizer} will iterate. + * Set the input text over which this {@code NormalizerBase} will iterate. * The iteration position is set to the beginning of the input text. * @param newText The new string to be normalized. * @stable ICU 2.8 */ public void setText(String newText) { - UCharacterIterator newIter = UCharacterIterator.getInstance(newText); if (newIter == null) { - throw new InternalError("Could not create a new UCharacterIterator"); + throw new IllegalStateException("Could not create a new UCharacterIterator"); } text = newIter; reset(); } /** - * Set the input text over which this {@code Normalizer} will iterate. + * Set the input text over which this {@code NormalizerBase} will iterate. * The iteration position is set to the beginning of the input text. * @param newText The new string to be normalized. * @stable ICU 2.8 */ public void setText(CharacterIterator newText) { - UCharacterIterator newIter = UCharacterIterator.getInstance(newText); if (newIter == null) { - throw new InternalError("Could not create a new UCharacterIterator"); + throw new IllegalStateException("Could not create a new UCharacterIterator"); } text = newIter; currentIndex=nextIndex=0; clearBuffer(); } - //------------------------------------------------------------------------- - // Private utility methods - //------------------------------------------------------------------------- - - - /* backward iteration --------------------------------------------------- */ - - /* - * read backwards and get norm32 - * return 0 if the character is <minC - * if c2!=0 then (c2, c) is a surrogate pair (reversed - c2 is first - * surrogate but read second!) - */ - - private static long getPrevNorm32(UCharacterIterator src, - int/*unsigned*/ minC, - int/*unsigned*/ mask, - char[] chars) { - long norm32; - int ch=0; - /* need src.hasPrevious() */ - if((ch=src.previous()) == UCharacterIterator.DONE) { - return 0; - } - chars[0]=(char)ch; - chars[1]=0; - - /* check for a surrogate before getting norm32 to see if we need to - * predecrement further */ - if(chars[0]<minC) { - return 0; - } else if(!UTF16.isSurrogate(chars[0])) { - return NormalizerImpl.getNorm32(chars[0]); - } else if(UTF16.isLeadSurrogate(chars[0]) || (src.getIndex()==0)) { - /* unpaired surrogate */ - chars[1]=(char)src.current(); - return 0; - } else if(UTF16.isLeadSurrogate(chars[1]=(char)src.previous())) { - norm32=NormalizerImpl.getNorm32(chars[1]); - if((norm32&mask)==0) { - /* all surrogate pairs with this lead surrogate have irrelevant - * data */ - return 0; - } else { - /* norm32 must be a surrogate special */ - return NormalizerImpl.getNorm32FromSurrogatePair(norm32,chars[0]); - } - } else { - /* unpaired second surrogate, undo the c2=src.previous() movement */ - src.moveIndex( 1); - return 0; - } - } - - private interface IsPrevBoundary{ - public boolean isPrevBoundary(UCharacterIterator src, - int/*unsigned*/ minC, - int/*unsigned*/ mask, - char[] chars); - } - private static final class IsPrevNFDSafe implements IsPrevBoundary{ - /* - * for NF*D: - * read backwards and check if the lead combining class is 0 - * if c2!=0 then (c2, c) is a surrogate pair (reversed - c2 is first - * surrogate but read second!) - */ - public boolean isPrevBoundary(UCharacterIterator src, - int/*unsigned*/ minC, - int/*unsigned*/ ccOrQCMask, - char[] chars) { - - return NormalizerImpl.isNFDSafe(getPrevNorm32(src, minC, - ccOrQCMask, chars), - ccOrQCMask, - ccOrQCMask& NormalizerImpl.QC_MASK); - } - } - - private static final class IsPrevTrueStarter implements IsPrevBoundary{ - /* - * read backwards and check if the character is (or its decomposition - * begins with) a "true starter" (cc==0 and NF*C_YES) - * if c2!=0 then (c2, c) is a surrogate pair (reversed - c2 is first - * surrogate but read second!) - */ - public boolean isPrevBoundary(UCharacterIterator src, - int/*unsigned*/ minC, - int/*unsigned*/ ccOrQCMask, - char[] chars) { - long norm32; - int/*unsigned*/ decompQCMask; - - decompQCMask=(ccOrQCMask<<2)&0xf; /*decomposition quick check mask*/ - norm32=getPrevNorm32(src, minC, ccOrQCMask|decompQCMask, chars); - return NormalizerImpl.isTrueStarter(norm32,ccOrQCMask,decompQCMask); - } - } - - private static int findPreviousIterationBoundary(UCharacterIterator src, - IsPrevBoundary obj, - int/*unsigned*/ minC, - int/*mask*/ mask, - char[] buffer, - int[] startIndex) { - char[] chars=new char[2]; - boolean isBoundary; - - /* fill the buffer from the end backwards */ - startIndex[0] = buffer.length; - chars[0]=0; - while(src.getIndex()>0 && chars[0]!=UCharacterIterator.DONE) { - isBoundary=obj.isPrevBoundary(src, minC, mask, chars); - - /* always write this character to the front of the buffer */ - /* make sure there is enough space in the buffer */ - if(startIndex[0] < (chars[1]==0 ? 1 : 2)) { - - // grow the buffer - char[] newBuf = new char[buffer.length*2]; - /* move the current buffer contents up */ - System.arraycopy(buffer,startIndex[0],newBuf, - newBuf.length-(buffer.length-startIndex[0]), - buffer.length-startIndex[0]); - //adjust the startIndex - startIndex[0]+=newBuf.length-buffer.length; - - buffer=newBuf; - newBuf=null; - - } - - buffer[--startIndex[0]]=chars[0]; - if(chars[1]!=0) { - buffer[--startIndex[0]]=chars[1]; - } - - /* stop if this just-copied character is a boundary */ - if(isBoundary) { - break; - } - } - - /* return the length of the buffer contents */ - return buffer.length-startIndex[0]; - } - - private static int previous(UCharacterIterator src, - char[] dest, int destStart, int destLimit, - Mode mode, - boolean doNormalize, - boolean[] pNeededToNormalize, - int options) { - - IsPrevBoundary isPreviousBoundary; - int destLength, bufferLength; - int/*unsigned*/ mask; - int c,c2; - - char minC; - int destCapacity = destLimit-destStart; - destLength=0; - - if(pNeededToNormalize!=null) { - pNeededToNormalize[0]=false; - } - minC = (char)mode.getMinC(); - mask = mode.getMask(); - isPreviousBoundary = mode.getPrevBoundary(); - - if(isPreviousBoundary==null) { - destLength=0; - if((c=src.previous())>=0) { - destLength=1; - if(UTF16.isTrailSurrogate((char)c)) { - c2= src.previous(); - if(c2!= UCharacterIterator.DONE) { - if(UTF16.isLeadSurrogate((char)c2)) { - if(destCapacity>=2) { - dest[1]=(char)c; // trail surrogate - destLength=2; - } - // lead surrogate to be written below - c=c2; - } else { - src.moveIndex(1); - } - } - } - - if(destCapacity>0) { - dest[0]=(char)c; - } - } - return destLength; - } - - char[] buffer = new char[100]; - int[] startIndex= new int[1]; - bufferLength=findPreviousIterationBoundary(src, - isPreviousBoundary, - minC, mask,buffer, - startIndex); - if(bufferLength>0) { - if(doNormalize) { - destLength=NormalizerBase.normalize(buffer,startIndex[0], - startIndex[0]+bufferLength, - dest, destStart,destLimit, - mode, options); - - if(pNeededToNormalize!=null) { - pNeededToNormalize[0]=destLength!=bufferLength || - Utility.arrayRegionMatches( - buffer,0,dest, - destStart,destLimit - ); - } - } else { - /* just copy the source characters */ - if(destCapacity>0) { - System.arraycopy(buffer,startIndex[0],dest,0, - (bufferLength<destCapacity) ? - bufferLength : destCapacity - ); - } - } - } - - - return destLength; - } - - - - /* forward iteration ---------------------------------------------------- */ - /* - * read forward and check if the character is a next-iteration boundary - * if c2!=0 then (c, c2) is a surrogate pair - */ - private interface IsNextBoundary{ - boolean isNextBoundary(UCharacterIterator src, - int/*unsigned*/ minC, - int/*unsigned*/ mask, - int[] chars); - } - /* - * read forward and get norm32 - * return 0 if the character is <minC - * if c2!=0 then (c2, c) is a surrogate pair - * always reads complete characters - */ - private static long /*unsigned*/ getNextNorm32(UCharacterIterator src, - int/*unsigned*/ minC, - int/*unsigned*/ mask, - int[] chars) { - long norm32; - - /* need src.hasNext() to be true */ - chars[0]=src.next(); - chars[1]=0; - - if(chars[0]<minC) { - return 0; - } - - norm32=NormalizerImpl.getNorm32((char)chars[0]); - if(UTF16.isLeadSurrogate((char)chars[0])) { - if(src.current()!=UCharacterIterator.DONE && - UTF16.isTrailSurrogate((char)(chars[1]=src.current()))) { - src.moveIndex(1); /* skip the c2 surrogate */ - if((norm32&mask)==0) { - /* irrelevant data */ - return 0; - } else { - /* norm32 must be a surrogate special */ - return NormalizerImpl.getNorm32FromSurrogatePair(norm32,(char)chars[1]); - } - } else { - /* unmatched surrogate */ - return 0; - } - } - return norm32; - } - - - /* - * for NF*D: - * read forward and check if the lead combining class is 0 - * if c2!=0 then (c, c2) is a surrogate pair - */ - private static final class IsNextNFDSafe implements IsNextBoundary{ - public boolean isNextBoundary(UCharacterIterator src, - int/*unsigned*/ minC, - int/*unsigned*/ ccOrQCMask, - int[] chars) { - return NormalizerImpl.isNFDSafe(getNextNorm32(src,minC,ccOrQCMask,chars), - ccOrQCMask, ccOrQCMask&NormalizerImpl.QC_MASK); - } - } - - /* - * for NF*C: - * read forward and check if the character is (or its decomposition begins - * with) a "true starter" (cc==0 and NF*C_YES) - * if c2!=0 then (c, c2) is a surrogate pair - */ - private static final class IsNextTrueStarter implements IsNextBoundary{ - public boolean isNextBoundary(UCharacterIterator src, - int/*unsigned*/ minC, - int/*unsigned*/ ccOrQCMask, - int[] chars) { - long norm32; - int/*unsigned*/ decompQCMask; - - decompQCMask=(ccOrQCMask<<2)&0xf; /*decomposition quick check mask*/ - norm32=getNextNorm32(src, minC, ccOrQCMask|decompQCMask, chars); - return NormalizerImpl.isTrueStarter(norm32, ccOrQCMask, decompQCMask); - } - } - - private static int findNextIterationBoundary(UCharacterIterator src, - IsNextBoundary obj, - int/*unsigned*/ minC, - int/*unsigned*/ mask, - char[] buffer) { - if(src.current()==UCharacterIterator.DONE) { - return 0; - } - - /* get one character and ignore its properties */ - int[] chars = new int[2]; - chars[0]=src.next(); - buffer[0]=(char)chars[0]; - int bufferIndex = 1; - - if(UTF16.isLeadSurrogate((char)chars[0])&& - src.current()!=UCharacterIterator.DONE) { - if(UTF16.isTrailSurrogate((char)(chars[1]=src.next()))) { - buffer[bufferIndex++]=(char)chars[1]; - } else { - src.moveIndex(-1); /* back out the non-trail-surrogate */ - } - } - - /* get all following characters until we see a boundary */ - /* checking hasNext() instead of c!=DONE on the off-chance that U+ffff - * is part of the string */ - while( src.current()!=UCharacterIterator.DONE) { - if(obj.isNextBoundary(src, minC, mask, chars)) { - /* back out the latest movement to stop at the boundary */ - src.moveIndex(chars[1]==0 ? -1 : -2); - break; - } else { - if(bufferIndex+(chars[1]==0 ? 1 : 2)<=buffer.length) { - buffer[bufferIndex++]=(char)chars[0]; - if(chars[1]!=0) { - buffer[bufferIndex++]=(char)chars[1]; - } - } else { - char[] newBuf = new char[buffer.length*2]; - System.arraycopy(buffer,0,newBuf,0,bufferIndex); - buffer = newBuf; - buffer[bufferIndex++]=(char)chars[0]; - if(chars[1]!=0) { - buffer[bufferIndex++]=(char)chars[1]; - } - } - } - } - - /* return the length of the buffer contents */ - return bufferIndex; - } - - private static int next(UCharacterIterator src, - char[] dest, int destStart, int destLimit, - NormalizerBase.Mode mode, - boolean doNormalize, - boolean[] pNeededToNormalize, - int options) { - - IsNextBoundary isNextBoundary; - int /*unsigned*/ mask; - int /*unsigned*/ bufferLength; - int c,c2; - char minC; - int destCapacity = destLimit - destStart; - int destLength = 0; - if(pNeededToNormalize!=null) { - pNeededToNormalize[0]=false; - } - - minC = (char)mode.getMinC(); - mask = mode.getMask(); - isNextBoundary = mode.getNextBoundary(); - - if(isNextBoundary==null) { - destLength=0; - c=src.next(); - if(c!=UCharacterIterator.DONE) { - destLength=1; - if(UTF16.isLeadSurrogate((char)c)) { - c2= src.next(); - if(c2!= UCharacterIterator.DONE) { - if(UTF16.isTrailSurrogate((char)c2)) { - if(destCapacity>=2) { - dest[1]=(char)c2; // trail surrogate - destLength=2; - } - // lead surrogate to be written below - } else { - src.moveIndex(-1); - } - } - } - - if(destCapacity>0) { - dest[0]=(char)c; - } - } - return destLength; - } - - char[] buffer=new char[100]; - int[] startIndex = new int[1]; - bufferLength=findNextIterationBoundary(src,isNextBoundary, minC, mask, - buffer); - if(bufferLength>0) { - if(doNormalize) { - destLength=mode.normalize(buffer,startIndex[0],bufferLength, - dest,destStart,destLimit, options); - - if(pNeededToNormalize!=null) { - pNeededToNormalize[0]=destLength!=bufferLength || - Utility.arrayRegionMatches(buffer,startIndex[0], - dest,destStart, - destLength); - } - } else { - /* just copy the source characters */ - if(destCapacity>0) { - System.arraycopy(buffer,0,dest,destStart, - Math.min(bufferLength,destCapacity) - ); - } - - - } - } - return destLength; - } - private void clearBuffer() { - bufferLimit=bufferStart=bufferPos=0; + buffer.setLength(0); + bufferPos=0; } private boolean nextNormalize() { - clearBuffer(); currentIndex=nextIndex; text.setIndex(nextIndex); - - bufferLimit=next(text,buffer,bufferStart,buffer.length,mode,true,null,options); - + // Skip at least one character so we make progress. + int c=text.nextCodePoint(); + if(c<0) { + return false; + } + StringBuilder segment=new StringBuilder().appendCodePoint(c); + while((c=text.nextCodePoint())>=0) { + if(norm2.hasBoundaryBefore(c)) { + text.moveCodePointIndex(-1); + break; + } + segment.appendCodePoint(c); + } nextIndex=text.getIndex(); - return (bufferLimit>0); + norm2.normalize(segment, buffer); + return buffer.length()!=0; } private boolean previousNormalize() { - clearBuffer(); nextIndex=currentIndex; text.setIndex(currentIndex); - bufferLimit=previous(text,buffer,bufferStart,buffer.length,mode,true,null,options); - + StringBuilder segment=new StringBuilder(); + int c; + while((c=text.previousCodePoint())>=0) { + if(c<=0xffff) { + segment.insert(0, (char)c); + } else { + segment.insert(0, Character.toChars(c)); + } + if(norm2.hasBoundaryBefore(c)) { + break; + } + } currentIndex=text.getIndex(); - bufferPos = bufferLimit; - return bufferLimit>0; + norm2.normalize(segment, buffer); + bufferPos=buffer.length(); + return buffer.length()!=0; } - private int getCodePointAt(int index) { - if( UTF16.isSurrogate(buffer[index])) { - if(UTF16.isLeadSurrogate(buffer[index])) { - if((index+1)<bufferLimit && - UTF16.isTrailSurrogate(buffer[index+1])) { - return UCharacterProperty.getRawSupplementary( - buffer[index], - buffer[index+1] - ); - } - }else if(UTF16.isTrailSurrogate(buffer[index])) { - if(index>0 && UTF16.isLeadSurrogate(buffer[index-1])) { - return UCharacterProperty.getRawSupplementary( - buffer[index-1], - buffer[index] - ); - } - } - } - return buffer[index]; - - } - - /** - * Internal API - * @internal - */ - public static boolean isNFSkippable(int c, Mode mode) { - return mode.isNFSkippable(c); - } - - // - // Options - // - - /* - * Default option for Unicode 3.2.0 normalization. - * Corrigendum 4 was fixed in Unicode 3.2.0 but isn't supported in - * IDNA/StringPrep. - * The public review issue #29 was fixed in Unicode 4.1.0. Corrigendum 5 - * allowed Unicode 3.2 to 4.0.1 to apply the fix for PRI #29, but it isn't - * supported by IDNA/StringPrep as well as Corrigendum 4. - */ - public static final int UNICODE_3_2_0_ORIGINAL = - UNICODE_3_2 | - NormalizerImpl.WITHOUT_CORRIGENDUM4_CORRECTIONS | - NormalizerImpl.BEFORE_PRI_29; - - /* - * Default option for the latest Unicode normalization. This option is - * provided mainly for testing. - * The value zero means that normalization is done with the fixes for - * - Corrigendum 4 (Five CJK Canonical Mapping Errors) - * - Corrigendum 5 (Normalization Idempotency) - */ - public static final int UNICODE_LATEST = 0x00; - - // - // public constructor and methods for java.text.Normalizer and - // sun.text.Normalizer - // - - /** - * Creates a new {@code Normalizer} object for iterating over the - * normalized form of a given string. - * - * @param str The string to be normalized. The normalization - * will start at the beginning of the string. - * - * @param mode The normalization mode. - */ - public NormalizerBase(String str, Mode mode) { - this(str, mode, UNICODE_LATEST); - } - - /** - * Normalizes a <code>String</code> using the given normalization form. - * - * @param str the input string to be normalized. - * @param form the normalization form - */ - public static String normalize(String str, Normalizer.Form form) { - return normalize(str, form, UNICODE_LATEST); - } - - /** - * Normalizes a <code>String</code> using the given normalization form. - * - * @param str the input string to be normalized. - * @param form the normalization form - * @param options the optional features to be enabled. - */ - public static String normalize(String str, Normalizer.Form form, int options) { - int len = str.length(); - boolean asciiOnly = true; - if (len < 80) { - for (int i = 0; i < len; i++) { - if (str.charAt(i) > 127) { - asciiOnly = false; - break; - } - } - } else { - char[] a = str.toCharArray(); - for (int i = 0; i < len; i++) { - if (a[i] > 127) { - asciiOnly = false; - break; - } - } - } - - switch (form) { - case NFC : - return asciiOnly ? str : NFC.normalize(str, options); - case NFD : - return asciiOnly ? str : NFD.normalize(str, options); - case NFKC : - return asciiOnly ? str : NFKC.normalize(str, options); - case NFKD : - return asciiOnly ? str : NFKD.normalize(str, options); - } - - throw new IllegalArgumentException("Unexpected normalization form: " + - form); - } - - /** - * Test if a string is in a given normalization form. - * This is semantically equivalent to source.equals(normalize(source, mode)). - * - * Unlike quickCheck(), this function returns a definitive result, - * never a "maybe". - * For NFD, NFKD, and FCD, both functions work exactly the same. - * For NFC and NFKC where quickCheck may return "maybe", this function will - * perform further tests to arrive at a true/false result. - * @param str the input string to be checked to see if it is normalized - * @param form the normalization form - */ - public static boolean isNormalized(String str, Normalizer.Form form) { - return isNormalized(str, form, UNICODE_LATEST); - } - - /** - * Test if a string is in a given normalization form. - * This is semantically equivalent to source.equals(normalize(source, mode)). - * - * Unlike quickCheck(), this function returns a definitive result, - * never a "maybe". - * For NFD, NFKD, and FCD, both functions work exactly the same. - * For NFC and NFKC where quickCheck may return "maybe", this function will - * perform further tests to arrive at a true/false result. - * @param str the input string to be checked to see if it is normalized - * @param form the normalization form - * @param options the optional features to be enabled. - */ - public static boolean isNormalized(String str, Normalizer.Form form, int options) { - switch (form) { - case NFC: - return (NFC.quickCheck(str.toCharArray(),0,str.length(),false,NormalizerImpl.getNX(options))==YES); - case NFD: - return (NFD.quickCheck(str.toCharArray(),0,str.length(),false,NormalizerImpl.getNX(options))==YES); - case NFKC: - return (NFKC.quickCheck(str.toCharArray(),0,str.length(),false,NormalizerImpl.getNX(options))==YES); - case NFKD: - return (NFKD.quickCheck(str.toCharArray(),0,str.length(),false,NormalizerImpl.getNX(options))==YES); - } - - throw new IllegalArgumentException("Unexpected normalization form: " + - form); - } } diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerDataReader.java b/jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerDataReader.java deleted file mode 100644 index 39bf4fe22c6..00000000000 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerDataReader.java +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. - * 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. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ - -package sun.text.normalizer; - -import java.io.DataInputStream; -import java.io.InputStream; -import java.io.IOException; - -/** - * @author Ram Viswanadha - */ - - /* - * Description of the format of unorm.icu version 2.1. - * - * Main change from version 1 to version 2: - * Use of new, common Trie instead of normalization-specific tries. - * Change to version 2.1: add third/auxiliary trie with associated data. - * - * For more details of how to use the data structures see the code - * in unorm.cpp (runtime normalization code) and - * in gennorm.c and gennorm/store.c (build-time data generation). - * - * For the serialized format of Trie see Trie.c/TrieHeader. - * - * - Overall partition - * - * unorm.icu customarily begins with a UDataInfo structure, see udata.h and .c. - * After that there are the following structures: - * - * char indexes[INDEX_TOP]; -- INDEX_TOP=32, see enum in this file - * - * Trie normTrie; -- size in bytes=indexes[INDEX_TRIE_SIZE] - * - * char extraData[extraDataTop]; -- extraDataTop=indexes[INDEX_UCHAR_COUNT] - * extraData[0] contains the number of units for - * FC_NFKC_Closure (formatVersion>=2.1) - * - * char combiningTable[combiningTableTop]; -- combiningTableTop=indexes[INDEX_COMBINE_DATA_COUNT] - * combiningTableTop may include one 16-bit padding unit - * to make sure that fcdTrie is 32-bit-aligned - * - * Trie fcdTrie; -- size in bytes=indexes[INDEX_FCD_TRIE_SIZE] - * - * Trie auxTrie; -- size in bytes=indexes[INDEX_AUX_TRIE_SIZE] - * - * - * The indexes array contains lengths and sizes of the following arrays and structures - * as well as the following values: - * indexes[INDEX_COMBINE_FWD_COUNT]=combineFwdTop - * -- one more than the highest combining index computed for forward-only-combining characters - * indexes[INDEX_COMBINE_BOTH_COUNT]=combineBothTop-combineFwdTop - * -- number of combining indexes computed for both-ways-combining characters - * indexes[INDEX_COMBINE_BACK_COUNT]=combineBackTop-combineBothTop - * -- number of combining indexes computed for backward-only-combining characters - * - * indexes[INDEX_MIN_NF*_NO_MAYBE] (where *={ C, D, KC, KD }) - * -- first code point with a quick check NF* value of NO/MAYBE - * - * - * - Tries - * - * The main structures are two Trie tables ("compact arrays"), - * each with one index array and one data array. - * See Trie.h and Trie.c. - * - * - * - Tries in unorm.icu - * - * The first trie (normTrie above) - * provides data for the NF* quick checks and normalization. - * The second trie (fcdTrie above) provides data just for FCD checks. - * - * - * - norm32 data words from the first trie - * - * The norm32Table contains one 32-bit word "norm32" per code point. - * It contains the following bit fields: - * 31..16 extra data index, EXTRA_SHIFT is used to shift this field down - * if this index is <EXTRA_INDEX_TOP then it is an index into - * extraData[] where variable-length normalization data for this - * code point is found - * if this index is <EXTRA_INDEX_TOP+EXTRA_SURROGATE_TOP - * then this is a norm32 for a leading surrogate, and the index - * value is used together with the following trailing surrogate - * code unit in the second trie access - * if this index is >=EXTRA_INDEX_TOP+EXTRA_SURROGATE_TOP - * then this is a norm32 for a "special" character, - * i.e., the character is a Hangul syllable or a Jamo - * see EXTRA_HANGUL etc. - * generally, instead of extracting this index from the norm32 and - * comparing it with the above constants, - * the normalization code compares the entire norm32 value - * with MIN_SPECIAL, SURROGATES_TOP, MIN_HANGUL etc. - * - * 15..8 combining class (cc) according to UnicodeData.txt - * - * 7..6 COMBINES_ANY flags, used in composition to see if a character - * combines with any following or preceding character(s) - * at all - * 7 COMBINES_BACK - * 6 COMBINES_FWD - * - * 5..0 quick check flags, set for "no" or "maybe", with separate flags for - * each normalization form - * the higher bits are "maybe" flags; for NF*D there are no such flags - * the lower bits are "no" flags for all forms, in the same order - * as the "maybe" flags, - * which is (MSB to LSB): NFKD NFD NFKC NFC - * 5..4 QC_ANY_MAYBE - * 3..0 QC_ANY_NO - * see further related constants - * - * - * - Extra data per code point - * - * "Extra data" is referenced by the index in norm32. - * It is variable-length data. It is only present, and only those parts - * of it are, as needed for a given character. - * The norm32 extra data index is added to the beginning of extraData[] - * to get to a vector of 16-bit words with data at the following offsets: - * - * [-1] Combining index for composition. - * Stored only if norm32&COMBINES_ANY . - * [0] Lengths of the canonical and compatibility decomposition strings. - * Stored only if there are decompositions, i.e., - * if norm32&(QC_NFD|QC_NFKD) - * High byte: length of NFKD, or 0 if none - * Low byte: length of NFD, or 0 if none - * Each length byte also has another flag: - * Bit 7 of a length byte is set if there are non-zero - * combining classes (cc's) associated with the respective - * decomposition. If this flag is set, then the decomposition - * is preceded by a 16-bit word that contains the - * leading and trailing cc's. - * Bits 6..0 of a length byte are the length of the - * decomposition string, not counting the cc word. - * [1..n] NFD - * [n+1..] NFKD - * - * Each of the two decompositions consists of up to two parts: - * - The 16-bit words with the leading and trailing cc's. - * This is only stored if bit 7 of the corresponding length byte - * is set. In this case, at least one of the cc's is not zero. - * High byte: leading cc==cc of the first code point in the decomposition string - * Low byte: trailing cc==cc of the last code point in the decomposition string - * - The decomposition string in UTF-16, with length code units. - * - * - * - Combining indexes and combiningTable[] - * - * Combining indexes are stored at the [-1] offset of the extra data - * if the character combines forward or backward with any other characters. - * They are used for (re)composition in NF*C. - * Values of combining indexes are arranged according to whether a character - * combines forward, backward, or both ways: - * forward-only < both ways < backward-only - * - * The index values for forward-only and both-ways combining characters - * are indexes into the combiningTable[]. - * The index values for backward-only combining characters are simply - * incremented from the preceding index values to be unique. - * - * In the combiningTable[], a variable-length list - * of variable-length (back-index, code point) pair entries is stored - * for each forward-combining character. - * - * These back-indexes are the combining indexes of both-ways or backward-only - * combining characters that the forward-combining character combines with. - * - * Each list is sorted in ascending order of back-indexes. - * Each list is terminated with the last back-index having bit 15 set. - * - * Each pair (back-index, code point) takes up either 2 or 3 - * 16-bit words. - * The first word of a list entry is the back-index, with its bit 15 set if - * this is the last pair in the list. - * - * The second word contains flags in bits 15..13 that determine - * if there is a third word and how the combined character is encoded: - * 15 set if there is a third word in this list entry - * 14 set if the result is a supplementary character - * 13 set if the result itself combines forward - * - * According to these bits 15..14 of the second word, - * the result character is encoded as follows: - * 00 or 01 The result is <=0x1fff and stored in bits 12..0 of - * the second word. - * 10 The result is 0x2000..0xffff and stored in the third word. - * Bits 12..0 of the second word are not used. - * 11 The result is a supplementary character. - * Bits 9..0 of the leading surrogate are in bits 9..0 of - * the second word. - * Add 0xd800 to these bits to get the complete surrogate. - * Bits 12..10 of the second word are not used. - * The trailing surrogate is stored in the third word. - * - * - * - FCD trie - * - * The FCD trie is very simple. - * It is a folded trie with 16-bit data words. - * In each word, the high byte contains the leading cc of the character, - * and the low byte contains the trailing cc of the character. - * These cc's are the cc's of the first and last code points in the - * canonical decomposition of the character. - * - * Since all 16 bits are used for cc's, lead surrogates must be tested - * by checking the code unit instead of the trie data. - * This is done only if the 16-bit data word is not zero. - * If the code unit is a leading surrogate and the data word is not zero, - * then instead of cc's it contains the offset for the second trie lookup. - * - * - * - Auxiliary trie and data - * - * - * The auxiliary 16-bit trie contains data for additional properties. - * Bits - * 15..13 reserved - * 12 not NFC_Skippable (f) (formatVersion>=2.2) - * 11 flag: not a safe starter for canonical closure - * 10 composition exclusion - * 9.. 0 index into extraData[] to FC_NFKC_Closure string - * (not for lead surrogate), - * or lead surrogate offset (for lead surrogate, if 9..0 not zero) - * - * Conditions for "NF* Skippable" from Mark Davis' com.ibm.text.UCD.NFSkippable: - * (used in NormalizerTransliterator) - * - * A skippable character is - * a) unassigned, or ALL of the following: - * b) of combining class 0. - * c) not decomposed by this normalization form. - * AND if NFC or NFKC, - * d) can never compose with a previous character. - * e) can never compose with a following character. - * f) can never change if another character is added. - * Example: a-breve might satisfy all but f, but if you - * add an ogonek it changes to a-ogonek + breve - * - * a)..e) must be tested from norm32. - * Since f) is more complicated, the (not-)NFC_Skippable flag (f) is built - * into the auxiliary trie. - * The same bit is used for NFC and NFKC; (c) differs for them. - * As usual, we build the "not skippable" flags so that unassigned - * code points get a 0 bit. - * This bit is only valid after (a)..(e) test FALSE; test NFD_NO before (f) as well. - * Test Hangul LV syllables entirely in code. - * - * - * - FC_NFKC_Closure strings in extraData[] - * - * Strings are either stored as a single code unit or as the length - * followed by that many units. - * - */ -final class NormalizerDataReader implements ICUBinary.Authenticate { - - /** - * <p>Protected constructor.</p> - * @param inputStream ICU uprop.dat file input stream - * @exception IOException throw if data file fails authentication - * @draft 2.1 - */ - protected NormalizerDataReader(InputStream inputStream) - throws IOException{ - - unicodeVersion = ICUBinary.readHeader(inputStream, DATA_FORMAT_ID, this); - dataInputStream = new DataInputStream(inputStream); - } - - // protected methods ------------------------------------------------- - - protected int[] readIndexes(int length)throws IOException{ - int[] indexes = new int[length]; - //Read the indexes - for (int i = 0; i <length ; i++) { - indexes[i] = dataInputStream.readInt(); - } - return indexes; - } - /** - * <p>Reads unorm.icu, parse it into blocks of data to be stored in - * NormalizerImpl.</P - * @param normBytes - * @param fcdBytes - * @param auxBytes - * @param extraData - * @param combiningTable - * @exception thrown when data reading fails - * @draft 2.1 - */ - protected void read(byte[] normBytes, byte[] fcdBytes, byte[] auxBytes, - char[] extraData, char[] combiningTable) - throws IOException{ - - //Read the bytes that make up the normTrie - dataInputStream.readFully(normBytes); - - //normTrieStream= new ByteArrayInputStream(normBytes); - - //Read the extra data - for(int i=0;i<extraData.length;i++){ - extraData[i]=dataInputStream.readChar(); - } - - //Read the combining class table - for(int i=0; i<combiningTable.length; i++){ - combiningTable[i]=dataInputStream.readChar(); - } - - //Read the fcdTrie - dataInputStream.readFully(fcdBytes); - - - //Read the AuxTrie - dataInputStream.readFully(auxBytes); - } - - public byte[] getDataFormatVersion(){ - return DATA_FORMAT_VERSION; - } - - public boolean isDataVersionAcceptable(byte version[]) - { - return version[0] == DATA_FORMAT_VERSION[0] - && version[2] == DATA_FORMAT_VERSION[2] - && version[3] == DATA_FORMAT_VERSION[3]; - } - - public byte[] getUnicodeVersion(){ - return unicodeVersion; - } - // private data members ------------------------------------------------- - - - /** - * ICU data file input stream - */ - private DataInputStream dataInputStream; - - private byte[] unicodeVersion; - - /** - * File format version that this class understands. - * No guarantees are made if a older version is used - * see store.c of gennorm for more information and values - */ - private static final byte DATA_FORMAT_ID[] = {(byte)0x4E, (byte)0x6F, - (byte)0x72, (byte)0x6D}; - private static final byte DATA_FORMAT_VERSION[] = {(byte)0x2, (byte)0x2, - (byte)0x5, (byte)0x2}; - -} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerImpl.java b/jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerImpl.java index 6981e1f4fd9..e00a7f9af5f 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerImpl.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/NormalizerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * 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,614 +22,1898 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. ******************************************************************************* */ package sun.text.normalizer; -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.BufferedInputStream; -import java.io.InputStream; +import java.nio.ByteBuffer; +import java.text.Normalizer; -/** - * @author Ram Viswanadha - */ +// Original filename in ICU4J: Normalizer2Impl.java public final class NormalizerImpl { - // Static block for the class to initialize its own self - static final NormalizerImpl IMPL; - static - { - try - { - IMPL = new NormalizerImpl(); - } - catch (Exception e) - { - throw new RuntimeException(e.getMessage()); - } - } + public static final class Hangul { + /* Korean Hangul and Jamo constants */ + public static final int JAMO_L_BASE=0x1100; /* "lead" jamo */ + public static final int JAMO_V_BASE=0x1161; /* "vowel" jamo */ + public static final int JAMO_T_BASE=0x11a7; /* "trail" jamo */ - static final int UNSIGNED_BYTE_MASK =0xFF; - static final long UNSIGNED_INT_MASK = 0xffffffffL; - /* - * This new implementation of the normalization code loads its data from - * unorm.icu, which is generated with the gennorm tool. - * The format of that file is described at the end of this file. - */ - private static final String DATA_FILE_NAME = "/sun/text/resources/unorm.icu"; + public static final int HANGUL_BASE=0xac00; + public static final int HANGUL_END=0xd7a3; - // norm32 value constants + public static final int JAMO_L_COUNT=19; + public static final int JAMO_V_COUNT=21; + public static final int JAMO_T_COUNT=28; - // quick check flags 0..3 set mean "no" for their forms - public static final int QC_NFC=0x11; /* no|maybe */ - public static final int QC_NFKC=0x22; /* no|maybe */ - public static final int QC_NFD=4; /* no */ - public static final int QC_NFKD=8; /* no */ + public static final int HANGUL_COUNT=JAMO_L_COUNT*JAMO_V_COUNT*JAMO_T_COUNT; + public static final int HANGUL_LIMIT=HANGUL_BASE+HANGUL_COUNT; - public static final int QC_ANY_NO=0xf; - - /* quick check flags 4..5 mean "maybe" for their forms; - * test flags>=QC_MAYBE - */ - public static final int QC_MAYBE=0x10; - public static final int QC_ANY_MAYBE=0x30; - - public static final int QC_MASK=0x3f; - - private static final int COMBINES_FWD=0x40; - private static final int COMBINES_BACK=0x80; - public static final int COMBINES_ANY=0xc0; - // UnicodeData.txt combining class in bits 15. - private static final int CC_SHIFT=8; - public static final int CC_MASK=0xff00; - // 16 bits for the index to UChars and other extra data - private static final int EXTRA_SHIFT=16; - - /* norm32 value constants using >16 bits */ - private static final long MIN_SPECIAL = 0xfc000000 & UNSIGNED_INT_MASK; - private static final long SURROGATES_TOP = 0xfff00000 & UNSIGNED_INT_MASK; - private static final long MIN_HANGUL = 0xfff00000 & UNSIGNED_INT_MASK; -// private static final long MIN_JAMO_V = 0xfff20000 & UNSIGNED_INT_MASK; - private static final long JAMO_V_TOP = 0xfff30000 & UNSIGNED_INT_MASK; - - - /* indexes[] value names */ - /* number of bytes in normalization trie */ - static final int INDEX_TRIE_SIZE = 0; - /* number of chars in extra data */ - static final int INDEX_CHAR_COUNT = 1; - /* number of uint16_t words for combining data */ - static final int INDEX_COMBINE_DATA_COUNT = 2; - /* first code point with quick check NFC NO/MAYBE */ - public static final int INDEX_MIN_NFC_NO_MAYBE = 6; - /* first code point with quick check NFKC NO/MAYBE */ - public static final int INDEX_MIN_NFKC_NO_MAYBE = 7; - /* first code point with quick check NFD NO/MAYBE */ - public static final int INDEX_MIN_NFD_NO_MAYBE = 8; - /* first code point with quick check NFKD NO/MAYBE */ - public static final int INDEX_MIN_NFKD_NO_MAYBE = 9; - /* number of bytes in FCD trie */ - static final int INDEX_FCD_TRIE_SIZE = 10; - /* number of bytes in the auxiliary trie */ - static final int INDEX_AUX_TRIE_SIZE = 11; - /* changing this requires a new formatVersion */ - static final int INDEX_TOP = 32; - - - /* AUX constants */ - /* value constants for auxTrie */ - private static final int AUX_UNSAFE_SHIFT = 11; - private static final int AUX_COMP_EX_SHIFT = 10; - private static final int AUX_NFC_SKIPPABLE_F_SHIFT = 12; - - private static final int AUX_MAX_FNC = 1<<AUX_COMP_EX_SHIFT; - private static final int AUX_UNSAFE_MASK = (int)((1<<AUX_UNSAFE_SHIFT) & UNSIGNED_INT_MASK); - private static final int AUX_FNC_MASK = (int)((AUX_MAX_FNC-1) & UNSIGNED_INT_MASK); - private static final int AUX_COMP_EX_MASK = (int)((1<<AUX_COMP_EX_SHIFT) & UNSIGNED_INT_MASK); - private static final long AUX_NFC_SKIP_F_MASK = ((UNSIGNED_INT_MASK&1)<<AUX_NFC_SKIPPABLE_F_SHIFT); - - private static final int MAX_BUFFER_SIZE = 20; - - /*******************************/ - - /* Wrappers for Trie implementations */ - static final class NormTrieImpl implements Trie.DataManipulate{ - static IntTrie normTrie= null; - /** - * Called by com.ibm.icu.util.Trie to extract from a lead surrogate's - * data the index array offset of the indexes for that lead surrogate. - * @param property data value for a surrogate from the trie, including - * the folding offset - * @return data offset or 0 if there is no data for the lead surrogate - */ - /* normTrie: 32-bit trie result may contain a special extraData index with the folding offset */ - public int getFoldingOffset(int value){ - return BMP_INDEX_LENGTH+ - ((value>>(EXTRA_SHIFT-SURROGATE_BLOCK_BITS))& - (0x3ff<<SURROGATE_BLOCK_BITS)); + public static boolean isHangul(int c) { + return HANGUL_BASE<=c && c<HANGUL_LIMIT; } - } - static final class FCDTrieImpl implements Trie.DataManipulate{ - static CharTrie fcdTrie=null; - /** - * Called by com.ibm.icu.util.Trie to extract from a lead surrogate's - * data the index array offset of the indexes for that lead surrogate. - * @param property data value for a surrogate from the trie, including - * the folding offset - * @return data offset or 0 if there is no data for the lead surrogate - */ - /* fcdTrie: the folding offset is the lead FCD value itself */ - public int getFoldingOffset(int value){ - return value; + public static boolean isHangulWithoutJamoT(char c) { + c-=HANGUL_BASE; + return c<HANGUL_COUNT && c%JAMO_T_COUNT==0; } - } - static final class AuxTrieImpl implements Trie.DataManipulate{ - static CharTrie auxTrie = null; - /** - * Called by com.ibm.icu.util.Trie to extract from a lead surrogate's - * data the index array offset of the indexes for that lead surrogate. - * @param property data value for a surrogate from the trie, including - * the folding offset - * @return data offset or 0 if there is no data for the lead surrogate - */ - /* auxTrie: the folding offset is in bits 9..0 of the 16-bit trie result */ - public int getFoldingOffset(int value){ - return (value &AUX_FNC_MASK)<<SURROGATE_BLOCK_BITS; - } - } - - /****************************************************/ - - - private static FCDTrieImpl fcdTrieImpl; - private static NormTrieImpl normTrieImpl; - private static AuxTrieImpl auxTrieImpl; - private static int[] indexes; - private static char[] combiningTable; - private static char[] extraData; - - private static boolean isDataLoaded; - private static boolean isFormatVersion_2_1; - private static boolean isFormatVersion_2_2; - private static byte[] unicodeVersion; - - /** - * Default buffer size of datafile - */ - private static final int DATA_BUFFER_SIZE = 25000; - - /** - * FCD check: everything below this code point is known to have a 0 - * lead combining class - */ - public static final int MIN_WITH_LEAD_CC=0x300; - - - /** - * Bit 7 of the length byte for a decomposition string in extra data is - * a flag indicating whether the decomposition string is - * preceded by a 16-bit word with the leading and trailing cc - * of the decomposition (like for A-umlaut); - * if not, then both cc's are zero (like for compatibility ideographs). - */ - private static final int DECOMP_FLAG_LENGTH_HAS_CC=0x80; - /** - * Bits 6..0 of the length byte contain the actual length. - */ - private static final int DECOMP_LENGTH_MASK=0x7f; - - /** Length of the BMP portion of the index (stage 1) array. */ - private static final int BMP_INDEX_LENGTH=0x10000>>Trie.INDEX_STAGE_1_SHIFT_; - /** Number of bits of a trail surrogate that are used in index table - * lookups. - */ - private static final int SURROGATE_BLOCK_BITS=10-Trie.INDEX_STAGE_1_SHIFT_; - - - // public utility - public static int getFromIndexesArr(int index){ - return indexes[index]; - } - - // protected constructor --------------------------------------------- - - /** - * Constructor - * @exception thrown when data reading fails or data corrupted - */ - private NormalizerImpl() throws IOException { - //data should be loaded only once - if(!isDataLoaded){ - - // jar access - InputStream i = ICUData.getRequiredStream(DATA_FILE_NAME); - BufferedInputStream b = new BufferedInputStream(i,DATA_BUFFER_SIZE); - NormalizerDataReader reader = new NormalizerDataReader(b); - - // read the indexes - indexes = reader.readIndexes(NormalizerImpl.INDEX_TOP); - - byte[] normBytes = new byte[indexes[NormalizerImpl.INDEX_TRIE_SIZE]]; - - int combiningTableTop = indexes[NormalizerImpl.INDEX_COMBINE_DATA_COUNT]; - combiningTable = new char[combiningTableTop]; - - int extraDataTop = indexes[NormalizerImpl.INDEX_CHAR_COUNT]; - extraData = new char[extraDataTop]; - - byte[] fcdBytes = new byte[indexes[NormalizerImpl.INDEX_FCD_TRIE_SIZE]]; - byte[] auxBytes = new byte[indexes[NormalizerImpl.INDEX_AUX_TRIE_SIZE]]; - - fcdTrieImpl = new FCDTrieImpl(); - normTrieImpl = new NormTrieImpl(); - auxTrieImpl = new AuxTrieImpl(); - - // load the rest of the data data and initialize the data members - reader.read(normBytes, fcdBytes,auxBytes, extraData, combiningTable); - - NormTrieImpl.normTrie = new IntTrie( new ByteArrayInputStream(normBytes),normTrieImpl ); - FCDTrieImpl.fcdTrie = new CharTrie( new ByteArrayInputStream(fcdBytes),fcdTrieImpl ); - AuxTrieImpl.auxTrie = new CharTrie( new ByteArrayInputStream(auxBytes),auxTrieImpl ); - - // we reached here without any exceptions so the data is fully - // loaded set the variable to true - isDataLoaded = true; - - // get the data format version - byte[] formatVersion = reader.getDataFormatVersion(); - - isFormatVersion_2_1 =( formatVersion[0]>2 - || - (formatVersion[0]==2 && formatVersion[1]>=1) - ); - isFormatVersion_2_2 =( formatVersion[0]>2 - || - (formatVersion[0]==2 && formatVersion[1]>=2) - ); - unicodeVersion = reader.getUnicodeVersion(); - b.close(); - } - } - - /* ---------------------------------------------------------------------- */ - - /* Korean Hangul and Jamo constants */ - - public static final int JAMO_L_BASE=0x1100; /* "lead" jamo */ - public static final int JAMO_V_BASE=0x1161; /* "vowel" jamo */ - public static final int JAMO_T_BASE=0x11a7; /* "trail" jamo */ - - public static final int HANGUL_BASE=0xac00; - - public static final int JAMO_L_COUNT=19; - public static final int JAMO_V_COUNT=21; - public static final int JAMO_T_COUNT=28; - public static final int HANGUL_COUNT=JAMO_L_COUNT*JAMO_V_COUNT*JAMO_T_COUNT; - - private static boolean isHangulWithoutJamoT(char c) { - c-=HANGUL_BASE; - return c<HANGUL_COUNT && c%JAMO_T_COUNT==0; - } - - /* norm32 helpers */ - - /* is this a norm32 with a regular index? */ - private static boolean isNorm32Regular(long norm32) { - return norm32<MIN_SPECIAL; - } - - /* is this a norm32 with a special index for a lead surrogate? */ - private static boolean isNorm32LeadSurrogate(long norm32) { - return MIN_SPECIAL<=norm32 && norm32<SURROGATES_TOP; - } - - /* is this a norm32 with a special index for a Hangul syllable or a Jamo? */ - private static boolean isNorm32HangulOrJamo(long norm32) { - return norm32>=MIN_HANGUL; - } - - /* - * Given norm32 for Jamo V or T, - * is this a Jamo V? - */ - private static boolean isJamoVTNorm32JamoV(long norm32) { - return norm32<JAMO_V_TOP; - } - - /* data access primitives ----------------------------------------------- */ - - public static long/*unsigned*/ getNorm32(char c) { - return ((UNSIGNED_INT_MASK) & (NormTrieImpl.normTrie.getLeadValue(c))); - } - - public static long/*unsigned*/ getNorm32FromSurrogatePair(long norm32, - char c2) { - /* - * the surrogate index in norm32 stores only the number of the surrogate - * index block see gennorm/store.c/getFoldedNormValue() + /** + * Decomposes c, which must be a Hangul syllable, into buffer + * and returns the length of the decomposition (2 or 3). */ - return ((UNSIGNED_INT_MASK) & - NormTrieImpl.normTrie.getTrailValue((int)norm32, c2)); - } - ///CLOVER:OFF - private static long getNorm32(int c){ - return (UNSIGNED_INT_MASK&(NormTrieImpl.normTrie.getCodePointValue(c))); - } - - /* - * get a norm32 from text with complete code points - * (like from decompositions) - */ - private static long/*unsigned*/ getNorm32(char[] p,int start, - int/*unsigned*/ mask) { - long/*unsigned*/ norm32= getNorm32(p[start]); - if(((norm32&mask)>0) && isNorm32LeadSurrogate(norm32)) { - /* *p is a lead surrogate, get the real norm32 */ - norm32=getNorm32FromSurrogatePair(norm32, p[start+1]); - } - return norm32; - } - - //// for StringPrep - public static VersionInfo getUnicodeVersion(){ - return VersionInfo.getInstance(unicodeVersion[0], unicodeVersion[1], - unicodeVersion[2], unicodeVersion[3]); - } - - public static char getFCD16(char c) { - return FCDTrieImpl.fcdTrie.getLeadValue(c); - } - - public static char getFCD16FromSurrogatePair(char fcd16, char c2) { - /* the surrogate index in fcd16 is an absolute offset over the - * start of stage 1 - * */ - return FCDTrieImpl.fcdTrie.getTrailValue(fcd16, c2); - } - public static int getFCD16(int c) { - return FCDTrieImpl.fcdTrie.getCodePointValue(c); - } - - private static int getExtraDataIndex(long norm32) { - return (int)(norm32>>EXTRA_SHIFT); - } - - private static final class DecomposeArgs{ - int /*unsigned byte*/ cc; - int /*unsigned byte*/ trailCC; - int length; - } - /** - * - * get the canonical or compatibility decomposition for one character - * - * @return index into the extraData array - */ - private static int/*index*/ decompose(long/*unsigned*/ norm32, - int/*unsigned*/ qcMask, - DecomposeArgs args) { - int p= getExtraDataIndex(norm32); - args.length=extraData[p++]; - - if((norm32&qcMask&QC_NFKD)!=0 && args.length>=0x100) { - /* use compatibility decomposition, skip canonical data */ - p+=((args.length>>7)&1)+(args.length&DECOMP_LENGTH_MASK); - args.length>>=8; - } - - if((args.length&DECOMP_FLAG_LENGTH_HAS_CC)>0) { - /* get the lead and trail cc's */ - char bothCCs=extraData[p++]; - args.cc=(UNSIGNED_BYTE_MASK) & (bothCCs>>8); - args.trailCC=(UNSIGNED_BYTE_MASK) & bothCCs; - } else { - /* lead and trail cc's are both 0 */ - args.cc=args.trailCC=0; - } - - args.length&=DECOMP_LENGTH_MASK; - return p; - } - - - /** - * get the canonical decomposition for one character - * @return index into the extraData array - */ - private static int decompose(long/*unsigned*/ norm32, - DecomposeArgs args) { - - int p= getExtraDataIndex(norm32); - args.length=extraData[p++]; - - if((args.length&DECOMP_FLAG_LENGTH_HAS_CC)>0) { - /* get the lead and trail cc's */ - char bothCCs=extraData[p++]; - args.cc=(UNSIGNED_BYTE_MASK) & (bothCCs>>8); - args.trailCC=(UNSIGNED_BYTE_MASK) & bothCCs; - } else { - /* lead and trail cc's are both 0 */ - args.cc=args.trailCC=0; - } - - args.length&=DECOMP_LENGTH_MASK; - return p; - } - - - private static final class NextCCArgs{ - char[] source; - int next; - int limit; - char c; - char c2; - } - - /* - * get the combining class of (c, c2)= args.source[args.next++] - * before: args.next<args.limit after: args.next<=args.limit - * if only one code unit is used, then c2==0 - */ - private static int /*unsigned byte*/ getNextCC(NextCCArgs args) { - long /*unsigned*/ norm32; - - args.c=args.source[args.next++]; - - norm32= getNorm32(args.c); - if((norm32 & CC_MASK)==0) { - args.c2=0; - return 0; - } else { - if(!isNorm32LeadSurrogate(norm32)) { - args.c2=0; - } else { - /* c is a lead surrogate, get the real norm32 */ - if(args.next!=args.limit && - UTF16.isTrailSurrogate(args.c2=args.source[args.next])){ - ++args.next; - norm32=getNorm32FromSurrogatePair(norm32, args.c2); + public static int decompose(int c, Appendable buffer) { + try { + c-=HANGUL_BASE; + int c2=c%JAMO_T_COUNT; + c/=JAMO_T_COUNT; + buffer.append((char)(JAMO_L_BASE+c/JAMO_V_COUNT)); + buffer.append((char)(JAMO_V_BASE+c%JAMO_V_COUNT)); + if(c2==0) { + return 2; } else { - args.c2=0; - return 0; + buffer.append((char)(JAMO_T_BASE+c2)); + return 3; } + } catch(IOException e) { + throw new InternalError(e); } - - return (int)((UNSIGNED_BYTE_MASK) & (norm32>>CC_SHIFT)); } } - private static final class PrevArgs{ - char[] src; - int start; - int current; - char c; - char c2; - } - - /* - * read backwards and get norm32 - * return 0 if the character is <minC - * if c2!=0 then (c2, c) is a surrogate pair (reversed - c2 is first - * surrogate but read second!) + /** + * Writable buffer that takes care of canonical ordering. + * Its Appendable methods behave like the C++ implementation's + * appendZeroCC() methods. + * <p> + * If dest is a StringBuilder, then the buffer writes directly to it. + * Otherwise, the buffer maintains a StringBuilder for intermediate text segments + * until no further changes are necessary and whole segments are appended. + * append() methods that take combining-class values always write to the StringBuilder. + * Other append() methods flush and append to the Appendable. */ - private static long /*unsigned*/ getPrevNorm32(PrevArgs args, - int/*unsigned*/ minC, - int/*unsigned*/ mask) { - long/*unsigned*/ norm32; - - args.c=args.src[--args.current]; - args.c2=0; - - /* check for a surrogate before getting norm32 to see if we need to - * predecrement further - */ - if(args.c<minC) { - return 0; - } else if(!UTF16.isSurrogate(args.c)) { - return getNorm32(args.c); - } else if(UTF16.isLeadSurrogate(args.c)) { - /* unpaired first surrogate */ - return 0; - } else if(args.current!=args.start && - UTF16.isLeadSurrogate(args.c2=args.src[args.current-1])) { - --args.current; - norm32=getNorm32(args.c2); - - if((norm32&mask)==0) { - /* all surrogate pairs with this lead surrogate have - * only irrelevant data - */ - return 0; + public static final class ReorderingBuffer implements Appendable { + public ReorderingBuffer(NormalizerImpl ni, Appendable dest, int destCapacity) { + impl=ni; + app=dest; + if (app instanceof StringBuilder) { + appIsStringBuilder=true; + str=(StringBuilder)dest; + // In Java, the constructor subsumes public void init(int destCapacity) + str.ensureCapacity(destCapacity); + reorderStart=0; + if(str.length()==0) { + lastCC=0; + } else { + setIterator(); + lastCC=previousCC(); + // Set reorderStart after the last code point with cc<=1 if there is one. + if(lastCC>1) { + while(previousCC()>1) {} + } + reorderStart=codePointLimit; + } } else { - /* norm32 must be a surrogate special */ - return getNorm32FromSurrogatePair(norm32, args.c); + appIsStringBuilder=false; + str=new StringBuilder(); + reorderStart=0; + lastCC=0; } + } + + public boolean isEmpty() { return str.length()==0; } + public int length() { return str.length(); } + public int getLastCC() { return lastCC; } + + public StringBuilder getStringBuilder() { return str; } + + public boolean equals(CharSequence s, int start, int limit) { + return UTF16Plus.equal(str, 0, str.length(), s, start, limit); + } + + // For Hangul composition, replacing the Leading consonant Jamo with the syllable. + public void setLastChar(char c) { + str.setCharAt(str.length()-1, c); + } + + public void append(int c, int cc) { + if(lastCC<=cc || cc==0) { + str.appendCodePoint(c); + lastCC=cc; + if(cc<=1) { + reorderStart=str.length(); + } + } else { + insert(c, cc); + } + } + + // s must be in NFD, otherwise change the implementation. + public void append(CharSequence s, int start, int limit, + int leadCC, int trailCC) { + if(start==limit) { + return; + } + if(lastCC<=leadCC || leadCC==0) { + if(trailCC<=1) { + reorderStart=str.length()+(limit-start); + } else if(leadCC<=1) { + reorderStart=str.length()+1; // Ok if not a code point boundary. + } + str.append(s, start, limit); + lastCC=trailCC; + } else { + int c=Character.codePointAt(s, start); + start+=Character.charCount(c); + insert(c, leadCC); // insert first code point + while(start<limit) { + c=Character.codePointAt(s, start); + start+=Character.charCount(c); + if(start<limit) { + // s must be in NFD, otherwise we need to use getCC(). + leadCC=getCCFromYesOrMaybe(impl.getNorm16(c)); + } else { + leadCC=trailCC; + } + append(c, leadCC); + } + } + } + + // The following append() methods work like C++ appendZeroCC(). + // They assume that the cc or trailCC of their input is 0. + // Most of them implement Appendable interface methods. + // @Override when we switch to Java 6 + public ReorderingBuffer append(char c) { + str.append(c); + lastCC=0; + reorderStart=str.length(); + return this; + } + + public void appendZeroCC(int c) { + str.appendCodePoint(c); + lastCC=0; + reorderStart=str.length(); + } + + // @Override when we switch to Java 6 + public ReorderingBuffer append(CharSequence s) { + if(s.length()!=0) { + str.append(s); + lastCC=0; + reorderStart=str.length(); + } + return this; + } + + // @Override when we switch to Java 6 + public ReorderingBuffer append(CharSequence s, int start, int limit) { + if(start!=limit) { + str.append(s, start, limit); + lastCC=0; + reorderStart=str.length(); + } + return this; + } + + /** + * Flushes from the intermediate StringBuilder to the Appendable, + * if they are different objects. + * Used after recomposition. + * Must be called at the end when writing to a non-StringBuilder Appendable. + */ + public void flush() { + if(appIsStringBuilder) { + reorderStart=str.length(); + } else { + try { + app.append(str); + str.setLength(0); + reorderStart=0; + } catch(IOException e) { + throw new InternalError(e); // Avoid declaring "throws IOException". + } + } + lastCC=0; + } + + /** + * Flushes from the intermediate StringBuilder to the Appendable, + * if they are different objects. + * Then appends the new text to the Appendable or StringBuilder. + * Normally used after quick check loops find a non-empty sequence. + */ + public ReorderingBuffer flushAndAppendZeroCC(CharSequence s, int start, int limit) { + if(appIsStringBuilder) { + str.append(s, start, limit); + reorderStart=str.length(); + } else { + try { + app.append(str).append(s, start, limit); + str.setLength(0); + reorderStart=0; + } catch(IOException e) { + throw new InternalError(e); // Avoid declaring "throws IOException". + } + } + lastCC=0; + return this; + } + + public void remove() { + str.setLength(0); + lastCC=0; + reorderStart=0; + } + + public void removeSuffix(int suffixLength) { + int oldLength=str.length(); + str.delete(oldLength-suffixLength, oldLength); + lastCC=0; + reorderStart=str.length(); + } + + // Inserts c somewhere before the last character. + // Requires 0<cc<lastCC which implies reorderStart<limit. + private void insert(int c, int cc) { + for(setIterator(), skipPrevious(); previousCC()>cc;) {} + // insert c at codePointLimit, after the character with prevCC<=cc + if(c<=0xffff) { + str.insert(codePointLimit, (char)c); + if(cc<=1) { + reorderStart=codePointLimit+1; + } + } else { + str.insert(codePointLimit, Character.toChars(c)); + if(cc<=1) { + reorderStart=codePointLimit+2; + } + } + } + + private final NormalizerImpl impl; + private final Appendable app; + private final StringBuilder str; + private final boolean appIsStringBuilder; + private int reorderStart; + private int lastCC; + + // private backward iterator + private void setIterator() { codePointStart=str.length(); } + private void skipPrevious() { // Requires 0<codePointStart. + codePointLimit=codePointStart; + codePointStart=str.offsetByCodePoints(codePointStart, -1); + } + private int previousCC() { // Returns 0 if there is no previous character. + codePointLimit=codePointStart; + if(reorderStart>=codePointStart) { + return 0; + } + int c=str.codePointBefore(codePointStart); + codePointStart-=Character.charCount(c); + if(c<MIN_CCC_LCCC_CP) { + return 0; + } + return getCCFromYesOrMaybe(impl.getNorm16(c)); + } + + private int codePointStart, codePointLimit; + } + + // TODO: Propose as public API on the UTF16 class. + // TODO: Propose widening UTF16 methods that take char to take int. + // TODO: Propose widening UTF16 methods that take String to take CharSequence. + public static final class UTF16Plus { + /** + * Assuming c is a surrogate code point (UTF16.isSurrogate(c)), + * is it a lead surrogate? + * @param c code unit or code point + * @return true or false + */ + public static boolean isSurrogateLead(int c) { return (c&0x400)==0; } + + /** + * Compares two CharSequence subsequences for binary equality. + * @param s1 first sequence + * @param start1 start offset in first sequence + * @param limit1 limit offset in first sequence + * @param s2 second sequence + * @param start2 start offset in second sequence + * @param limit2 limit offset in second sequence + * @return true if s1.subSequence(start1, limit1) contains the same text + * as s2.subSequence(start2, limit2) + */ + public static boolean equal(CharSequence s1, int start1, int limit1, + CharSequence s2, int start2, int limit2) { + if((limit1-start1)!=(limit2-start2)) { + return false; + } + if(s1==s2 && start1==start2) { + return true; + } + while(start1<limit1) { + if(s1.charAt(start1++)!=s2.charAt(start2++)) { + return false; + } + } + return true; + } + } + + public NormalizerImpl() {} + + private static final class IsAcceptable implements ICUBinary.Authenticate { + // @Override when we switch to Java 6 + public boolean isDataVersionAcceptable(byte version[]) { + return version[0]==2; + } + } + + private static final IsAcceptable IS_ACCEPTABLE = new IsAcceptable(); + private static final int DATA_FORMAT = 0x4e726d32; // "Nrm2" + + public NormalizerImpl load(ByteBuffer bytes) { + try { + dataVersion=ICUBinary.readHeaderAndDataVersion(bytes, DATA_FORMAT, IS_ACCEPTABLE); + int indexesLength=bytes.getInt()/4; // inIndexes[IX_NORM_TRIE_OFFSET]/4 + if(indexesLength<=IX_MIN_MAYBE_YES) { + throw new IOException("Normalizer2 data: not enough indexes"); + } + int[] inIndexes=new int[indexesLength]; + inIndexes[0]=indexesLength*4; + for(int i=1; i<indexesLength; ++i) { + inIndexes[i]=bytes.getInt(); + } + + minDecompNoCP=inIndexes[IX_MIN_DECOMP_NO_CP]; + minCompNoMaybeCP=inIndexes[IX_MIN_COMP_NO_MAYBE_CP]; + + minYesNo=inIndexes[IX_MIN_YES_NO]; + minYesNoMappingsOnly=inIndexes[IX_MIN_YES_NO_MAPPINGS_ONLY]; + minNoNo=inIndexes[IX_MIN_NO_NO]; + limitNoNo=inIndexes[IX_LIMIT_NO_NO]; + minMaybeYes=inIndexes[IX_MIN_MAYBE_YES]; + + // Read the normTrie. + int offset=inIndexes[IX_NORM_TRIE_OFFSET]; + int nextOffset=inIndexes[IX_EXTRA_DATA_OFFSET]; + normTrie=Trie2_16.createFromSerialized(bytes); + int trieLength=normTrie.getSerializedLength(); + if(trieLength>(nextOffset-offset)) { + throw new IOException("Normalizer2 data: not enough bytes for normTrie"); + } + ICUBinary.skipBytes(bytes, (nextOffset-offset)-trieLength); // skip padding after trie bytes + + // Read the composition and mapping data. + offset=nextOffset; + nextOffset=inIndexes[IX_SMALL_FCD_OFFSET]; + int numChars=(nextOffset-offset)/2; + char[] chars; + if(numChars!=0) { + chars=new char[numChars]; + for(int i=0; i<numChars; ++i) { + chars[i]=bytes.getChar(); + } + maybeYesCompositions=new String(chars); + extraData=maybeYesCompositions.substring(MIN_NORMAL_MAYBE_YES-minMaybeYes); + } + + // smallFCD: new in formatVersion 2 + offset=nextOffset; + smallFCD=new byte[0x100]; + for(int i=0; i<0x100; ++i) { + smallFCD[i]=bytes.get(); + } + + // Build tccc180[]. + // gennorm2 enforces lccc=0 for c<MIN_CCC_LCCC_CP=U+0300. + tccc180=new int[0x180]; + int bits=0; + for(int c=0; c<0x180; bits>>=1) { + if((c&0xff)==0) { + bits=smallFCD[c>>8]; // one byte per 0x100 code points + } + if((bits&1)!=0) { + for(int i=0; i<0x20; ++i, ++c) { + tccc180[c]=getFCD16FromNormData(c)&0xff; + } + } else { + c+=0x20; + } + } + + return this; + } catch(IOException e) { + throw new InternalError(e); + } + } + + public NormalizerImpl load(String name) { + return load(ICUBinary.getRequiredData(name)); + } + + public int getNorm16(int c) { + return normTrie.get(c); + } + + public boolean isDecompYes(int norm16) { return norm16<minYesNo || minMaybeYes<=norm16; } + + public int getCC(int norm16) { + if(norm16>=MIN_NORMAL_MAYBE_YES) { + return norm16&0xff; + } + if(norm16<minNoNo || limitNoNo<=norm16) { + return 0; + } + return getCCFromNoNo(norm16); + } + + public static int getCCFromYesOrMaybe(int norm16) { + return norm16>=MIN_NORMAL_MAYBE_YES ? norm16&0xff : 0; + } + + /** + * Returns the FCD data for code point c. + * @param c A Unicode code point. + * @return The lccc(c) in bits 15..8 and tccc(c) in bits 7..0. + */ + public int getFCD16(int c) { + if(c<0) { + return 0; + } else if(c<0x180) { + return tccc180[c]; + } else if(c<=0xffff) { + if(!singleLeadMightHaveNonZeroFCD16(c)) { return 0; } + } + return getFCD16FromNormData(c); + } + + /** Returns the FCD data for U+0000<=c<U+0180. */ + public int getFCD16FromBelow180(int c) { return tccc180[c]; } + /** Returns true if the single-or-lead code unit c might have non-zero FCD data. */ + public boolean singleLeadMightHaveNonZeroFCD16(int lead) { + // 0<=lead<=0xffff + byte bits=smallFCD[lead>>8]; + if(bits==0) { return false; } + return ((bits>>((lead>>5)&7))&1)!=0; + } + + /** Gets the FCD value from the regular normalization data. */ + public int getFCD16FromNormData(int c) { + // Only loops for 1:1 algorithmic mappings. + for(;;) { + int norm16=getNorm16(c); + if(norm16<=minYesNo) { + // no decomposition or Hangul syllable, all zeros + return 0; + } else if(norm16>=MIN_NORMAL_MAYBE_YES) { + // combining mark + norm16&=0xff; + return norm16|(norm16<<8); + } else if(norm16>=minMaybeYes) { + return 0; + } else if(isDecompNoAlgorithmic(norm16)) { + c=mapAlgorithmic(c, norm16); + } else { + // c decomposes, get everything from the variable-length extra data + int firstUnit=extraData.charAt(norm16); + if((firstUnit&MAPPING_LENGTH_MASK)==0) { + // A character that is deleted (maps to an empty string) must + // get the worst-case lccc and tccc values because arbitrary + // characters on both sides will become adjacent. + return 0x1ff; + } else { + int fcd16=firstUnit>>8; // tccc + if((firstUnit&MAPPING_HAS_CCC_LCCC_WORD)!=0) { + fcd16|=extraData.charAt(norm16-1)&0xff00; // lccc + } + return fcd16; + } + } + } + } + + /** + * Gets the decomposition for one code point. + * @param c code point + * @return c's decomposition, if it has one; returns null if it does not have a decomposition + */ + public String getDecomposition(int c) { + int decomp=-1; + int norm16; + for(;;) { + if(c<minDecompNoCP || isDecompYes(norm16=getNorm16(c))) { + // c does not decompose + } else if(isHangul(norm16)) { + // Hangul syllable: decompose algorithmically + StringBuilder buffer=new StringBuilder(); + Hangul.decompose(c, buffer); + return buffer.toString(); + } else if(isDecompNoAlgorithmic(norm16)) { + decomp=c=mapAlgorithmic(c, norm16); + continue; + } else { + // c decomposes, get everything from the variable-length extra data + int length=extraData.charAt(norm16++)&MAPPING_LENGTH_MASK; + return extraData.substring(norm16, norm16+length); + } + if(decomp<0) { + return null; + } else { + return UTF16.valueOf(decomp); + } + } + } + + public static final int MIN_CCC_LCCC_CP=0x300; + + public static final int MIN_YES_YES_WITH_CC=0xff01; + public static final int JAMO_VT=0xff00; + public static final int MIN_NORMAL_MAYBE_YES=0xfe00; + public static final int MAX_DELTA=0x40; + + // Byte offsets from the start of the data, after the generic header. + public static final int IX_NORM_TRIE_OFFSET=0; + public static final int IX_EXTRA_DATA_OFFSET=1; + public static final int IX_SMALL_FCD_OFFSET=2; + + // Code point thresholds for quick check codes. + public static final int IX_MIN_DECOMP_NO_CP=8; + public static final int IX_MIN_COMP_NO_MAYBE_CP=9; + + // Norm16 value thresholds for quick check combinations and types of extra data. + // Mappings & compositions in [minYesNo..minYesNoMappingsOnly[. + public static final int IX_MIN_YES_NO=10; + public static final int IX_MIN_NO_NO=11; + public static final int IX_LIMIT_NO_NO=12; + public static final int IX_MIN_MAYBE_YES=13; + + // Mappings only in [minYesNoMappingsOnly..minNoNo[. + public static final int IX_MIN_YES_NO_MAPPINGS_ONLY=14; + + public static final int MAPPING_HAS_CCC_LCCC_WORD=0x80; + public static final int MAPPING_LENGTH_MASK=0x1f; + + public static final int COMP_1_LAST_TUPLE=0x8000; + public static final int COMP_1_TRIPLE=1; + public static final int COMP_1_TRAIL_LIMIT=0x3400; + public static final int COMP_1_TRAIL_MASK=0x7ffe; + public static final int COMP_1_TRAIL_SHIFT=9; // 10-1 for the "triple" bit + public static final int COMP_2_TRAIL_SHIFT=6; + public static final int COMP_2_TRAIL_MASK=0xffc0; + + // higher-level functionality ------------------------------------------ *** + + /** + * Decomposes s[src, limit[ and writes the result to dest. + * limit can be NULL if src is NUL-terminated. + * destLengthEstimate is the initial dest buffer capacity and can be -1. + */ + public void decompose(CharSequence s, int src, int limit, StringBuilder dest, + int destLengthEstimate) { + if(destLengthEstimate<0) { + destLengthEstimate=limit-src; + } + dest.setLength(0); + ReorderingBuffer buffer=new ReorderingBuffer(this, dest, destLengthEstimate); + decompose(s, src, limit, buffer); + } + + // Dual functionality: + // buffer!=NULL: normalize + // buffer==NULL: isNormalized/quickCheck/spanQuickCheckYes + public int decompose(CharSequence s, int src, int limit, + ReorderingBuffer buffer) { + int minNoCP=minDecompNoCP; + + int prevSrc; + int c=0; + int norm16=0; + + // only for quick check + int prevBoundary=src; + int prevCC=0; + + for(;;) { + // count code units below the minimum or with irrelevant data for the quick check + for(prevSrc=src; src!=limit;) { + if( (c=s.charAt(src))<minNoCP || + isMostDecompYesAndZeroCC(norm16=normTrie.getFromU16SingleLead((char)c)) + ) { + ++src; + } else if(!UTF16.isSurrogate((char)c)) { + break; + } else { + char c2; + if(UTF16Plus.isSurrogateLead(c)) { + if((src+1)!=limit && Character.isLowSurrogate(c2=s.charAt(src+1))) { + c=Character.toCodePoint((char)c, c2); + } + } else /* trail surrogate */ { + if(prevSrc<src && Character.isHighSurrogate(c2=s.charAt(src-1))) { + --src; + c=Character.toCodePoint(c2, (char)c); + } + } + if(isMostDecompYesAndZeroCC(norm16=getNorm16(c))) { + src+=Character.charCount(c); + } else { + break; + } + } + } + // copy these code units all at once + if(src!=prevSrc) { + if(buffer!=null) { + buffer.flushAndAppendZeroCC(s, prevSrc, src); + } else { + prevCC=0; + prevBoundary=src; + } + } + if(src==limit) { + break; + } + + // Check one above-minimum, relevant code point. + src+=Character.charCount(c); + if(buffer!=null) { + decompose(c, norm16, buffer); + } else { + if(isDecompYes(norm16)) { + int cc=getCCFromYesOrMaybe(norm16); + if(prevCC<=cc || cc==0) { + prevCC=cc; + if(cc<=1) { + prevBoundary=src; + } + continue; + } + } + return prevBoundary; // "no" or cc out of order + } + } + return src; + } + + public void decomposeAndAppend(CharSequence s, boolean doDecompose, ReorderingBuffer buffer) { + int limit=s.length(); + if(limit==0) { + return; + } + if(doDecompose) { + decompose(s, 0, limit, buffer); + return; + } + // Just merge the strings at the boundary. + int c=Character.codePointAt(s, 0); + int src=0; + int firstCC, prevCC, cc; + firstCC=prevCC=cc=getCC(getNorm16(c)); + while(cc!=0) { + prevCC=cc; + src+=Character.charCount(c); + if(src>=limit) { + break; + } + c=Character.codePointAt(s, src); + cc=getCC(getNorm16(c)); + }; + buffer.append(s, 0, src, firstCC, prevCC); + buffer.append(s, src, limit); + } + + // Very similar to composeQuickCheck(): Make the same changes in both places if relevant. + // doCompose: normalize + // !doCompose: isNormalized (buffer must be empty and initialized) + public boolean compose(CharSequence s, int src, int limit, + boolean onlyContiguous, + boolean doCompose, + ReorderingBuffer buffer) { + int minNoMaybeCP=minCompNoMaybeCP; + + /* + * prevBoundary points to the last character before the current one + * that has a composition boundary before it with ccc==0 and quick check "yes". + * Keeping track of prevBoundary saves us looking for a composition boundary + * when we find a "no" or "maybe". + * + * When we back out from prevSrc back to prevBoundary, + * then we also remove those same characters (which had been simply copied + * or canonically-order-inserted) from the ReorderingBuffer. + * Therefore, at all times, the [prevBoundary..prevSrc[ source units + * must correspond 1:1 to destination units at the end of the destination buffer. + */ + int prevBoundary=src; + int prevSrc; + int c=0; + int norm16=0; + + // only for isNormalized + int prevCC=0; + + for(;;) { + // count code units below the minimum or with irrelevant data for the quick check + for(prevSrc=src; src!=limit;) { + if( (c=s.charAt(src))<minNoMaybeCP || + isCompYesAndZeroCC(norm16=normTrie.getFromU16SingleLead((char)c)) + ) { + ++src; + } else if(!UTF16.isSurrogate((char)c)) { + break; + } else { + char c2; + if(UTF16Plus.isSurrogateLead(c)) { + if((src+1)!=limit && Character.isLowSurrogate(c2=s.charAt(src+1))) { + c=Character.toCodePoint((char)c, c2); + } + } else /* trail surrogate */ { + if(prevSrc<src && Character.isHighSurrogate(c2=s.charAt(src-1))) { + --src; + c=Character.toCodePoint(c2, (char)c); + } + } + if(isCompYesAndZeroCC(norm16=getNorm16(c))) { + src+=Character.charCount(c); + } else { + break; + } + } + } + // copy these code units all at once + if(src!=prevSrc) { + if(src==limit) { + if(doCompose) { + buffer.flushAndAppendZeroCC(s, prevSrc, src); + } + break; + } + // Set prevBoundary to the last character in the quick check loop. + prevBoundary=src-1; + if( Character.isLowSurrogate(s.charAt(prevBoundary)) && prevSrc<prevBoundary && + Character.isHighSurrogate(s.charAt(prevBoundary-1)) + ) { + --prevBoundary; + } + if(doCompose) { + // The last "quick check yes" character is excluded from the + // flush-and-append call in case it needs to be modified. + buffer.flushAndAppendZeroCC(s, prevSrc, prevBoundary); + buffer.append(s, prevBoundary, src); + } else { + prevCC=0; + } + // The start of the current character (c). + prevSrc=src; + } else if(src==limit) { + break; + } + + src+=Character.charCount(c); + /* + * isCompYesAndZeroCC(norm16) is false, that is, norm16>=minNoNo. + * c is either a "noNo" (has a mapping) or a "maybeYes" (combines backward) + * or has ccc!=0. + * Check for Jamo V/T, then for regular characters. + * c is not a Hangul syllable or Jamo L because those have "yes" properties. + */ + if(isJamoVT(norm16) && prevBoundary!=prevSrc) { + char prev=s.charAt(prevSrc-1); + boolean needToDecompose=false; + if(c<Hangul.JAMO_T_BASE) { + // c is a Jamo Vowel, compose with previous Jamo L and following Jamo T. + prev-=Hangul.JAMO_L_BASE; + if(prev<Hangul.JAMO_L_COUNT) { + if(!doCompose) { + return false; + } + char syllable=(char) + (Hangul.HANGUL_BASE+ + (prev*Hangul.JAMO_V_COUNT+(c-Hangul.JAMO_V_BASE))* + Hangul.JAMO_T_COUNT); + char t; + if(src!=limit && (t=(char)(s.charAt(src)-Hangul.JAMO_T_BASE))<Hangul.JAMO_T_COUNT) { + ++src; + syllable+=t; // The next character was a Jamo T. + prevBoundary=src; + buffer.setLastChar(syllable); + continue; + } + // If we see L+V+x where x!=T then we drop to the slow path, + // decompose and recompose. + // This is to deal with NFKC finding normal L and V but a + // compatibility variant of a T. We need to either fully compose that + // combination here (which would complicate the code and may not work + // with strange custom data) or use the slow path -- or else our replacing + // two input characters (L+V) with one output character (LV syllable) + // would violate the invariant that [prevBoundary..prevSrc[ has the same + // length as what we appended to the buffer since prevBoundary. + needToDecompose=true; + } + } else if(Hangul.isHangulWithoutJamoT(prev)) { + // c is a Jamo Trailing consonant, + // compose with previous Hangul LV that does not contain a Jamo T. + if(!doCompose) { + return false; + } + buffer.setLastChar((char)(prev+c-Hangul.JAMO_T_BASE)); + prevBoundary=src; + continue; + } + if(!needToDecompose) { + // The Jamo V/T did not compose into a Hangul syllable. + if(doCompose) { + buffer.append((char)c); + } else { + prevCC=0; + } + continue; + } + } + /* + * Source buffer pointers: + * + * all done quick check current char not yet + * "yes" but (c) processed + * may combine + * forward + * [-------------[-------------[-------------[-------------[ + * | | | | | + * orig. src prevBoundary prevSrc src limit + * + * + * Destination buffer pointers inside the ReorderingBuffer: + * + * all done might take not filled yet + * characters for + * reordering + * [-------------[-------------[-------------[ + * | | | | + * start reorderStart limit | + * +remainingCap.+ + */ + if(norm16>=MIN_YES_YES_WITH_CC) { + int cc=norm16&0xff; // cc!=0 + if( onlyContiguous && // FCC + (doCompose ? buffer.getLastCC() : prevCC)==0 && + prevBoundary<prevSrc && + // buffer.getLastCC()==0 && prevBoundary<prevSrc tell us that + // [prevBoundary..prevSrc[ (which is exactly one character under these conditions) + // passed the quick check "yes && ccc==0" test. + // Check whether the last character was a "yesYes" or a "yesNo". + // If a "yesNo", then we get its trailing ccc from its + // mapping and check for canonical order. + // All other cases are ok. + getTrailCCFromCompYesAndZeroCC(s, prevBoundary, prevSrc)>cc + ) { + // Fails FCD test, need to decompose and contiguously recompose. + if(!doCompose) { + return false; + } + } else if(doCompose) { + buffer.append(c, cc); + continue; + } else if(prevCC<=cc) { + prevCC=cc; + continue; + } else { + return false; + } + } else if(!doCompose && !isMaybeOrNonZeroCC(norm16)) { + return false; + } + + /* + * Find appropriate boundaries around this character, + * decompose the source text from between the boundaries, + * and recompose it. + * + * We may need to remove the last few characters from the ReorderingBuffer + * to account for source text that was copied or appended + * but needs to take part in the recomposition. + */ + + /* + * Find the last composition boundary in [prevBoundary..src[. + * It is either the decomposition of the current character (at prevSrc), + * or prevBoundary. + */ + if(hasCompBoundaryBefore(c, norm16)) { + prevBoundary=prevSrc; + } else if(doCompose) { + buffer.removeSuffix(prevSrc-prevBoundary); + } + + // Find the next composition boundary in [src..limit[ - + // modifies src to point to the next starter. + src=findNextCompBoundary(s, src, limit); + + // Decompose [prevBoundary..src[ into the buffer and then recompose that part of it. + int recomposeStartIndex=buffer.length(); + decomposeShort(s, prevBoundary, src, buffer); + recompose(buffer, recomposeStartIndex, onlyContiguous); + if(!doCompose) { + if(!buffer.equals(s, prevBoundary, src)) { + return false; + } + buffer.remove(); + prevCC=0; + } + + // Move to the next starter. We never need to look back before this point again. + prevBoundary=src; + } + return true; + } + + /** + * Very similar to compose(): Make the same changes in both places if relevant. + * doSpan: spanQuickCheckYes (ignore bit 0 of the return value) + * !doSpan: quickCheck + * @return bits 31..1: spanQuickCheckYes (==s.length() if "yes") and + * bit 0: set if "maybe"; otherwise, if the span length<s.length() + * then the quick check result is "no" + */ + public int composeQuickCheck(CharSequence s, int src, int limit, + boolean onlyContiguous, boolean doSpan) { + int qcResult=0; + int minNoMaybeCP=minCompNoMaybeCP; + + /* + * prevBoundary points to the last character before the current one + * that has a composition boundary before it with ccc==0 and quick check "yes". + */ + int prevBoundary=src; + int prevSrc; + int c=0; + int norm16=0; + int prevCC=0; + + for(;;) { + // count code units below the minimum or with irrelevant data for the quick check + for(prevSrc=src;;) { + if(src==limit) { + return (src<<1)|qcResult; // "yes" or "maybe" + } + if( (c=s.charAt(src))<minNoMaybeCP || + isCompYesAndZeroCC(norm16=normTrie.getFromU16SingleLead((char)c)) + ) { + ++src; + } else if(!UTF16.isSurrogate((char)c)) { + break; + } else { + char c2; + if(UTF16Plus.isSurrogateLead(c)) { + if((src+1)!=limit && Character.isLowSurrogate(c2=s.charAt(src+1))) { + c=Character.toCodePoint((char)c, c2); + } + } else /* trail surrogate */ { + if(prevSrc<src && Character.isHighSurrogate(c2=s.charAt(src-1))) { + --src; + c=Character.toCodePoint(c2, (char)c); + } + } + if(isCompYesAndZeroCC(norm16=getNorm16(c))) { + src+=Character.charCount(c); + } else { + break; + } + } + } + if(src!=prevSrc) { + // Set prevBoundary to the last character in the quick check loop. + prevBoundary=src-1; + if( Character.isLowSurrogate(s.charAt(prevBoundary)) && prevSrc<prevBoundary && + Character.isHighSurrogate(s.charAt(prevBoundary-1)) + ) { + --prevBoundary; + } + prevCC=0; + // The start of the current character (c). + prevSrc=src; + } + + src+=Character.charCount(c); + /* + * isCompYesAndZeroCC(norm16) is false, that is, norm16>=minNoNo. + * c is either a "noNo" (has a mapping) or a "maybeYes" (combines backward) + * or has ccc!=0. + */ + if(isMaybeOrNonZeroCC(norm16)) { + int cc=getCCFromYesOrMaybe(norm16); + if( onlyContiguous && // FCC + cc!=0 && + prevCC==0 && + prevBoundary<prevSrc && + // prevCC==0 && prevBoundary<prevSrc tell us that + // [prevBoundary..prevSrc[ (which is exactly one character under these conditions) + // passed the quick check "yes && ccc==0" test. + // Check whether the last character was a "yesYes" or a "yesNo". + // If a "yesNo", then we get its trailing ccc from its + // mapping and check for canonical order. + // All other cases are ok. + getTrailCCFromCompYesAndZeroCC(s, prevBoundary, prevSrc)>cc + ) { + // Fails FCD test. + } else if(prevCC<=cc || cc==0) { + prevCC=cc; + if(norm16<MIN_YES_YES_WITH_CC) { + if(!doSpan) { + qcResult=1; + } else { + return prevBoundary<<1; // spanYes does not care to know it's "maybe" + } + } + continue; + } + } + return prevBoundary<<1; // "no" + } + } + + public void composeAndAppend(CharSequence s, + boolean doCompose, + boolean onlyContiguous, + ReorderingBuffer buffer) { + int src=0, limit=s.length(); + if(!buffer.isEmpty()) { + int firstStarterInSrc=findNextCompBoundary(s, 0, limit); + if(0!=firstStarterInSrc) { + int lastStarterInDest=findPreviousCompBoundary(buffer.getStringBuilder(), + buffer.length()); + StringBuilder middle=new StringBuilder((buffer.length()-lastStarterInDest)+ + firstStarterInSrc+16); + middle.append(buffer.getStringBuilder(), lastStarterInDest, buffer.length()); + buffer.removeSuffix(buffer.length()-lastStarterInDest); + middle.append(s, 0, firstStarterInSrc); + compose(middle, 0, middle.length(), onlyContiguous, true, buffer); + src=firstStarterInSrc; + } + } + if(doCompose) { + compose(s, src, limit, onlyContiguous, true, buffer); + } else { + buffer.append(s, src, limit); + } + } + + // Dual functionality: + // buffer!=NULL: normalize + // buffer==NULL: isNormalized/quickCheck/spanQuickCheckYes + public int makeFCD(CharSequence s, int src, int limit, ReorderingBuffer buffer) { + // Note: In this function we use buffer->appendZeroCC() because we track + // the lead and trail combining classes here, rather than leaving it to + // the ReorderingBuffer. + // The exception is the call to decomposeShort() which uses the buffer + // in the normal way. + + // Tracks the last FCD-safe boundary, before lccc=0 or after properly-ordered tccc<=1. + // Similar to the prevBoundary in the compose() implementation. + int prevBoundary=src; + int prevSrc; + int c=0; + int prevFCD16=0; + int fcd16=0; + + for(;;) { + // count code units with lccc==0 + for(prevSrc=src; src!=limit;) { + if((c=s.charAt(src))<MIN_CCC_LCCC_CP) { + prevFCD16=~c; + ++src; + } else if(!singleLeadMightHaveNonZeroFCD16(c)) { + prevFCD16=0; + ++src; + } else { + if(UTF16.isSurrogate((char)c)) { + char c2; + if(UTF16Plus.isSurrogateLead(c)) { + if((src+1)!=limit && Character.isLowSurrogate(c2=s.charAt(src+1))) { + c=Character.toCodePoint((char)c, c2); + } + } else /* trail surrogate */ { + if(prevSrc<src && Character.isHighSurrogate(c2=s.charAt(src-1))) { + --src; + c=Character.toCodePoint(c2, (char)c); + } + } + } + if((fcd16=getFCD16FromNormData(c))<=0xff) { + prevFCD16=fcd16; + src+=Character.charCount(c); + } else { + break; + } + } + } + // copy these code units all at once + if(src!=prevSrc) { + if(src==limit) { + if(buffer!=null) { + buffer.flushAndAppendZeroCC(s, prevSrc, src); + } + break; + } + prevBoundary=src; + // We know that the previous character's lccc==0. + if(prevFCD16<0) { + // Fetching the fcd16 value was deferred for this below-U+0300 code point. + int prev=~prevFCD16; + prevFCD16= prev<0x180 ? tccc180[prev] : getFCD16FromNormData(prev); + if(prevFCD16>1) { + --prevBoundary; + } + } else { + int p=src-1; + if( Character.isLowSurrogate(s.charAt(p)) && prevSrc<p && + Character.isHighSurrogate(s.charAt(p-1)) + ) { + --p; + // Need to fetch the previous character's FCD value because + // prevFCD16 was just for the trail surrogate code point. + prevFCD16=getFCD16FromNormData(Character.toCodePoint(s.charAt(p), s.charAt(p+1))); + // Still known to have lccc==0 because its lead surrogate unit had lccc==0. + } + if(prevFCD16>1) { + prevBoundary=p; + } + } + if(buffer!=null) { + // The last lccc==0 character is excluded from the + // flush-and-append call in case it needs to be modified. + buffer.flushAndAppendZeroCC(s, prevSrc, prevBoundary); + buffer.append(s, prevBoundary, src); + } + // The start of the current character (c). + prevSrc=src; + } else if(src==limit) { + break; + } + + src+=Character.charCount(c); + // The current character (c) at [prevSrc..src[ has a non-zero lead combining class. + // Check for proper order, and decompose locally if necessary. + if((prevFCD16&0xff)<=(fcd16>>8)) { + // proper order: prev tccc <= current lccc + if((fcd16&0xff)<=1) { + prevBoundary=src; + } + if(buffer!=null) { + buffer.appendZeroCC(c); + } + prevFCD16=fcd16; + continue; + } else if(buffer==null) { + return prevBoundary; // quick check "no" + } else { + /* + * Back out the part of the source that we copied or appended + * already but is now going to be decomposed. + * prevSrc is set to after what was copied/appended. + */ + buffer.removeSuffix(prevSrc-prevBoundary); + /* + * Find the part of the source that needs to be decomposed, + * up to the next safe boundary. + */ + src=findNextFCDBoundary(s, src, limit); + /* + * The source text does not fulfill the conditions for FCD. + * Decompose and reorder a limited piece of the text. + */ + decomposeShort(s, prevBoundary, src, buffer); + prevBoundary=src; + prevFCD16=0; + } + } + return src; + } + + // Note: hasDecompBoundary() could be implemented as aliases to + // hasFCDBoundaryBefore() and hasFCDBoundaryAfter() + // at the cost of building the FCD trie for a decomposition normalizer. + public boolean hasDecompBoundary(int c, boolean before) { + for(;;) { + if(c<minDecompNoCP) { + return true; + } + int norm16=getNorm16(c); + if(isHangul(norm16) || isDecompYesAndZeroCC(norm16)) { + return true; + } else if(norm16>MIN_NORMAL_MAYBE_YES) { + return false; // ccc!=0 + } else if(isDecompNoAlgorithmic(norm16)) { + c=mapAlgorithmic(c, norm16); + } else { + // c decomposes, get everything from the variable-length extra data + int firstUnit=extraData.charAt(norm16); + if((firstUnit&MAPPING_LENGTH_MASK)==0) { + return false; + } + if(!before) { + // decomp after-boundary: same as hasFCDBoundaryAfter(), + // fcd16<=1 || trailCC==0 + if(firstUnit>0x1ff) { + return false; // trailCC>1 + } + if(firstUnit<=0xff) { + return true; // trailCC==0 + } + // if(trailCC==1) test leadCC==0, same as checking for before-boundary + } + // true if leadCC==0 (hasFCDBoundaryBefore()) + return (firstUnit&MAPPING_HAS_CCC_LCCC_WORD)==0 || (extraData.charAt(norm16-1)&0xff00)==0; + } + } + } + + public boolean hasCompBoundaryBefore(int c) { + return c<minCompNoMaybeCP || hasCompBoundaryBefore(c, getNorm16(c)); + } + + private boolean isMaybe(int norm16) { return minMaybeYes<=norm16 && norm16<=JAMO_VT; } + private boolean isMaybeOrNonZeroCC(int norm16) { return norm16>=minMaybeYes; } + private static boolean isJamoVT(int norm16) { return norm16==JAMO_VT; } + private boolean isHangul(int norm16) { return norm16==minYesNo; } + private boolean isCompYesAndZeroCC(int norm16) { return norm16<minNoNo; } + + // UBool isCompYes(uint16_t norm16) const { + // return norm16>=MIN_YES_YES_WITH_CC || norm16<minNoNo; + // } + // UBool isCompYesOrMaybe(uint16_t norm16) const { + // return norm16<minNoNo || minMaybeYes<=norm16; + // } + // private boolean hasZeroCCFromDecompYes(int norm16) { + // return norm16<=MIN_NORMAL_MAYBE_YES || norm16==JAMO_VT; + // } + private boolean isDecompYesAndZeroCC(int norm16) { + return norm16<minYesNo || + norm16==JAMO_VT || + (minMaybeYes<=norm16 && norm16<=MIN_NORMAL_MAYBE_YES); + } + + /** + * A little faster and simpler than isDecompYesAndZeroCC() but does not include + * the MaybeYes which combine-forward and have ccc=0. + * (Standard Unicode 5.2 normalization does not have such characters.) + */ + private boolean isMostDecompYesAndZeroCC(int norm16) { + return norm16<minYesNo || norm16==MIN_NORMAL_MAYBE_YES || norm16==JAMO_VT; + } + + private boolean isDecompNoAlgorithmic(int norm16) { return norm16>=limitNoNo; } + + // For use with isCompYes(). + // Perhaps the compiler can combine the two tests for MIN_YES_YES_WITH_CC. + // static uint8_t getCCFromYes(uint16_t norm16) { + // return norm16>=MIN_YES_YES_WITH_CC ? (uint8_t)norm16 : 0; + // } + private int getCCFromNoNo(int norm16) { + if((extraData.charAt(norm16)&MAPPING_HAS_CCC_LCCC_WORD)!=0) { + return extraData.charAt(norm16-1)&0xff; } else { - /* unpaired second surrogate */ - args.c2=0; return 0; } } - /* - * get the combining class of (c, c2)=*--p - * before: start<p after: start<=p - */ - private static int /*unsigned byte*/ getPrevCC(PrevArgs args) { - - return (int)((UNSIGNED_BYTE_MASK)&(getPrevNorm32(args, MIN_WITH_LEAD_CC, - CC_MASK)>>CC_SHIFT)); - } - - /* - * is this a safe boundary character for NF*D? - * (lead cc==0) - */ - public static boolean isNFDSafe(long/*unsigned*/ norm32, - int/*unsigned*/ccOrQCMask, - int/*unsigned*/ decompQCMask) { - if((norm32&ccOrQCMask)==0) { - return true; /* cc==0 and no decomposition: this is NF*D safe */ - } - - /* inspect its decomposition - maybe a Hangul but not a surrogate here*/ - if(isNorm32Regular(norm32) && (norm32&decompQCMask)!=0) { - DecomposeArgs args=new DecomposeArgs(); - /* decomposes, get everything from the variable-length extra data */ - decompose(norm32, decompQCMask, args); - return args.cc==0; + // requires that the [cpStart..cpLimit[ character passes isCompYesAndZeroCC() + int getTrailCCFromCompYesAndZeroCC(CharSequence s, int cpStart, int cpLimit) { + int c; + if(cpStart==(cpLimit-1)) { + c=s.charAt(cpStart); } else { - /* no decomposition (or Hangul), test the cc directly */ - return (norm32&CC_MASK)==0; + c=Character.codePointAt(s, cpStart); + } + int prevNorm16=getNorm16(c); + if(prevNorm16<=minYesNo) { + return 0; // yesYes and Hangul LV/LVT have ccc=tccc=0 + } else { + return extraData.charAt(prevNorm16)>>8; // tccc from yesNo } } - /* - * is this (or does its decomposition begin with) a "true starter"? - * (cc==0 and NF*C_YES) + // Requires algorithmic-NoNo. + private int mapAlgorithmic(int c, int norm16) { + return c+norm16-(minMaybeYes-MAX_DELTA-1); + } + + // Requires minYesNo<norm16<limitNoNo. + // private int getMapping(int norm16) { return /*extraData+*/norm16; } + + /** + * @return index into maybeYesCompositions, or -1 */ - public static boolean isTrueStarter(long/*unsigned*/ norm32, - int/*unsigned*/ ccOrQCMask, - int/*unsigned*/ decompQCMask) { - if((norm32&ccOrQCMask)==0) { - return true; /* this is a true starter (could be Hangul or Jamo L)*/ + private int getCompositionsListForDecompYes(int norm16) { + if(norm16==0 || MIN_NORMAL_MAYBE_YES<=norm16) { + return -1; + } else { + if((norm16-=minMaybeYes)<0) { + // norm16<minMaybeYes: index into extraData which is a substring at + // maybeYesCompositions[MIN_NORMAL_MAYBE_YES-minMaybeYes] + // same as (MIN_NORMAL_MAYBE_YES-minMaybeYes)+norm16 + norm16+=MIN_NORMAL_MAYBE_YES; // for yesYes; if Jamo L: harmless empty list + } + return norm16; } + } - /* inspect its decomposition - not a Hangul or a surrogate here */ - if((norm32&decompQCMask)!=0) { - int p; /* index into extra data array */ - DecomposeArgs args=new DecomposeArgs(); - /* decomposes, get everything from the variable-length extra data */ - p=decompose(norm32, decompQCMask, args); + /** + * @return index into maybeYesCompositions + */ + private int getCompositionsListForComposite(int norm16) { + // composite has both mapping & compositions list + int firstUnit=extraData.charAt(norm16); + return (MIN_NORMAL_MAYBE_YES-minMaybeYes)+norm16+ // mapping in maybeYesCompositions + 1+ // +1 to skip the first unit with the mapping lenth + (firstUnit&MAPPING_LENGTH_MASK); // + mapping length + } - if(args.cc==0) { - int/*unsigned*/ qcMask=ccOrQCMask&QC_MASK; + // Decompose a short piece of text which is likely to contain characters that + // fail the quick check loop and/or where the quick check loop's overhead + // is unlikely to be amortized. + // Called by the compose() and makeFCD() implementations. + // Public in Java for collation implementation code. + public void decomposeShort(CharSequence s, int src, int limit, + ReorderingBuffer buffer) { + while(src<limit) { + int c=Character.codePointAt(s, src); + src+=Character.charCount(c); + decompose(c, getNorm16(c), buffer); + } + } - /* does it begin with NFC_YES? */ - if((getNorm32(extraData,p, qcMask)&qcMask)==0) { - /* yes, the decomposition begins with a true starter */ - return true; + private void decompose(int c, int norm16, + ReorderingBuffer buffer) { + // Only loops for 1:1 algorithmic mappings. + for(;;) { + // get the decomposition and the lead and trail cc's + if(isDecompYes(norm16)) { + // c does not decompose + buffer.append(c, getCCFromYesOrMaybe(norm16)); + } else if(isHangul(norm16)) { + // Hangul syllable: decompose algorithmically + Hangul.decompose(c, buffer); + } else if(isDecompNoAlgorithmic(norm16)) { + c=mapAlgorithmic(c, norm16); + norm16=getNorm16(c); + continue; + } else { + // c decomposes, get everything from the variable-length extra data + int firstUnit=extraData.charAt(norm16); + int length=firstUnit&MAPPING_LENGTH_MASK; + int leadCC, trailCC; + trailCC=firstUnit>>8; + if((firstUnit&MAPPING_HAS_CCC_LCCC_WORD)!=0) { + leadCC=extraData.charAt(norm16-1)>>8; + } else { + leadCC=0; + } + ++norm16; // skip over the firstUnit + buffer.append(extraData, norm16, norm16+length, leadCC, trailCC); + } + return; + } + } + + /** + * Finds the recomposition result for + * a forward-combining "lead" character, + * specified with a pointer to its compositions list, + * and a backward-combining "trail" character. + * + * <p>If the lead and trail characters combine, then this function returns + * the following "compositeAndFwd" value: + * <pre> + * Bits 21..1 composite character + * Bit 0 set if the composite is a forward-combining starter + * </pre> + * otherwise it returns -1. + * + * <p>The compositions list has (trail, compositeAndFwd) pair entries, + * encoded as either pairs or triples of 16-bit units. + * The last entry has the high bit of its first unit set. + * + * <p>The list is sorted by ascending trail characters (there are no duplicates). + * A linear search is used. + * + * <p>See normalizer2impl.h for a more detailed description + * of the compositions list format. + */ + private static int combine(String compositions, int list, int trail) { + int key1, firstUnit; + if(trail<COMP_1_TRAIL_LIMIT) { + // trail character is 0..33FF + // result entry may have 2 or 3 units + key1=(trail<<1); + while(key1>(firstUnit=compositions.charAt(list))) { + list+=2+(firstUnit&COMP_1_TRIPLE); + } + if(key1==(firstUnit&COMP_1_TRAIL_MASK)) { + if((firstUnit&COMP_1_TRIPLE)!=0) { + return ((int)compositions.charAt(list+1)<<16)|compositions.charAt(list+2); + } else { + return compositions.charAt(list+1); + } + } + } else { + // trail character is 3400..10FFFF + // result entry has 3 units + key1=COMP_1_TRAIL_LIMIT+(((trail>>COMP_1_TRAIL_SHIFT))&~COMP_1_TRIPLE); + int key2=(trail<<COMP_2_TRAIL_SHIFT)&0xffff; + int secondUnit; + for(;;) { + if(key1>(firstUnit=compositions.charAt(list))) { + list+=2+(firstUnit&COMP_1_TRIPLE); + } else if(key1==(firstUnit&COMP_1_TRAIL_MASK)) { + if(key2>(secondUnit=compositions.charAt(list+1))) { + if((firstUnit&COMP_1_LAST_TUPLE)!=0) { + break; + } else { + list+=3; + } + } else if(key2==(secondUnit&COMP_2_TRAIL_MASK)) { + return ((secondUnit&~COMP_2_TRAIL_MASK)<<16)|compositions.charAt(list+2); + } else { + break; + } + } else { + break; } } } - return false; + return -1; } - /* reorder UTF-16 in-place ---------------------------------------------- */ + /* + * Recomposes the buffer text starting at recomposeStartIndex + * (which is in NFD - decomposed and canonically ordered), + * and truncates the buffer contents. + * + * Note that recomposition never lengthens the text: + * Any character consists of either one or two code units; + * a composition may contain at most one more code unit than the original starter, + * while the combining mark that is removed has at least one code unit. + */ + private void recompose(ReorderingBuffer buffer, int recomposeStartIndex, + boolean onlyContiguous) { + StringBuilder sb=buffer.getStringBuilder(); + int p=recomposeStartIndex; + if(p==sb.length()) { + return; + } + + int starter, pRemove; + int compositionsList; + int c, compositeAndFwd; + int norm16; + int cc, prevCC; + boolean starterIsSupplementary; + + // Some of the following variables are not used until we have a forward-combining starter + // and are only initialized now to avoid compiler warnings. + compositionsList=-1; // used as indicator for whether we have a forward-combining starter + starter=-1; + starterIsSupplementary=false; + prevCC=0; + + for(;;) { + c=sb.codePointAt(p); + p+=Character.charCount(c); + norm16=getNorm16(c); + cc=getCCFromYesOrMaybe(norm16); + if( // this character combines backward and + isMaybe(norm16) && + // we have seen a starter that combines forward and + compositionsList>=0 && + // the backward-combining character is not blocked + (prevCC<cc || prevCC==0)) { + if(isJamoVT(norm16)) { + // c is a Jamo V/T, see if we can compose it with the previous character. + if(c<Hangul.JAMO_T_BASE) { + // c is a Jamo Vowel, compose with previous Jamo L and following Jamo T. + char prev=(char)(sb.charAt(starter)-Hangul.JAMO_L_BASE); + if(prev<Hangul.JAMO_L_COUNT) { + pRemove=p-1; + char syllable=(char) + (Hangul.HANGUL_BASE+ + (prev*Hangul.JAMO_V_COUNT+(c-Hangul.JAMO_V_BASE))* + Hangul.JAMO_T_COUNT); + char t; + if(p!=sb.length() && (t=(char)(sb.charAt(p)-Hangul.JAMO_T_BASE))<Hangul.JAMO_T_COUNT) { + ++p; + syllable+=t; // The next character was a Jamo T. + } + sb.setCharAt(starter, syllable); + // remove the Jamo V/T + sb.delete(pRemove, p); + p=pRemove; + } + } + /* + * No "else" for Jamo T: + * Since the input is in NFD, there are no Hangul LV syllables that + * a Jamo T could combine with. + * All Jamo Ts are combined above when handling Jamo Vs. + */ + if(p==sb.length()) { + break; + } + compositionsList=-1; + continue; + } else if((compositeAndFwd=combine(maybeYesCompositions, compositionsList, c))>=0) { + // The starter and the combining mark (c) do combine. + int composite=compositeAndFwd>>1; + + // Remove the combining mark. + pRemove=p-Character.charCount(c); // pRemove & p: start & limit of the combining mark + sb.delete(pRemove, p); + p=pRemove; + // Replace the starter with the composite. + if(starterIsSupplementary) { + if(composite>0xffff) { + // both are supplementary + sb.setCharAt(starter, UTF16.getLeadSurrogate(composite)); + sb.setCharAt(starter+1, UTF16.getTrailSurrogate(composite)); + } else { + sb.setCharAt(starter, (char)c); + sb.deleteCharAt(starter+1); + // The composite is shorter than the starter, + // move the intermediate characters forward one. + starterIsSupplementary=false; + --p; + } + } else if(composite>0xffff) { + // The composite is longer than the starter, + // move the intermediate characters back one. + starterIsSupplementary=true; + sb.setCharAt(starter, UTF16.getLeadSurrogate(composite)); + sb.insert(starter+1, UTF16.getTrailSurrogate(composite)); + ++p; + } else { + // both are on the BMP + sb.setCharAt(starter, (char)composite); + } + + // Keep prevCC because we removed the combining mark. + + if(p==sb.length()) { + break; + } + // Is the composite a starter that combines forward? + if((compositeAndFwd&1)!=0) { + compositionsList= + getCompositionsListForComposite(getNorm16(composite)); + } else { + compositionsList=-1; + } + + // We combined; continue with looking for compositions. + continue; + } + } + + // no combination this time + prevCC=cc; + if(p==sb.length()) { + break; + } + + // If c did not combine, then check if it is a starter. + if(cc==0) { + // Found a new starter. + if((compositionsList=getCompositionsListForDecompYes(norm16))>=0) { + // It may combine with something, prepare for it. + if(c<=0xffff) { + starterIsSupplementary=false; + starter=p-1; + } else { + starterIsSupplementary=true; + starter=p-2; + } + } + } else if(onlyContiguous) { + // FCC: no discontiguous compositions; any intervening character blocks. + compositionsList=-1; + } + } + buffer.flush(); + } + + /** + * Does c have a composition boundary before it? + * True if its decomposition begins with a character that has + * ccc=0 && NFC_QC=Yes (isCompYesAndZeroCC()). + * As a shortcut, this is true if c itself has ccc=0 && NFC_QC=Yes + * (isCompYesAndZeroCC()) so we need not decompose. + */ + private boolean hasCompBoundaryBefore(int c, int norm16) { + for(;;) { + if(isCompYesAndZeroCC(norm16)) { + return true; + } else if(isMaybeOrNonZeroCC(norm16)) { + return false; + } else if(isDecompNoAlgorithmic(norm16)) { + c=mapAlgorithmic(c, norm16); + norm16=getNorm16(c); + } else { + // c decomposes, get everything from the variable-length extra data + int firstUnit=extraData.charAt(norm16); + if((firstUnit&MAPPING_LENGTH_MASK)==0) { + return false; + } + if((firstUnit&MAPPING_HAS_CCC_LCCC_WORD)!=0 && (extraData.charAt(norm16-1)&0xff00)!=0) { + return false; // non-zero leadCC + } + return isCompYesAndZeroCC(getNorm16(Character.codePointAt(extraData, norm16+1))); + } + } + } + + private int findPreviousCompBoundary(CharSequence s, int p) { + while(p>0) { + int c=Character.codePointBefore(s, p); + p-=Character.charCount(c); + if(hasCompBoundaryBefore(c)) { + break; + } + // We could also test hasCompBoundaryAfter() and return iter.codePointLimit, + // but that's probably not worth the extra cost. + } + return p; + } + + private int findNextCompBoundary(CharSequence s, int p, int limit) { + while(p<limit) { + int c=Character.codePointAt(s, p); + int norm16=normTrie.get(c); + if(hasCompBoundaryBefore(c, norm16)) { + break; + } + p+=Character.charCount(c); + } + return p; + } + + private int findNextFCDBoundary(CharSequence s, int p, int limit) { + while(p<limit) { + int c=Character.codePointAt(s, p); + if(c<MIN_CCC_LCCC_CP || getFCD16(c)<=0xff) { + break; + } + p+=Character.charCount(c); + } + return p; + } + + /** + * Get the canonical decomposition + * sherman for ComposedCharIter + */ + public static int getDecompose(int chars[], String decomps[]) { + Normalizer2 impl = Normalizer2.getNFDInstance(); + + int length=0; + int norm16 = 0; + int ch = -1; + int i = 0; + + while (++ch < 0x2fa1e) { //no cannoical above 0x3ffff + //TBD !!!! the hack code heres save us about 50ms for startup + //need a better solution/lookup + if (ch == 0x30ff) + ch = 0xf900; + else if (ch == 0x115bc) + ch = 0x1d15e; + else if (ch == 0x1d1c1) + ch = 0x2f800; + + String s = impl.getDecomposition(ch); + + if(s != null && i < chars.length) { + chars[i] = ch; + decomps[i++] = s; + } + } + return i; + } + + //------------------------------------------------------ + // special method for Collation (RBTableBuilder.build()) + //------------------------------------------------------ + private static boolean needSingleQuotation(char c) { + return (c >= 0x0009 && c <= 0x000D) || + (c >= 0x0020 && c <= 0x002F) || + (c >= 0x003A && c <= 0x0040) || + (c >= 0x005B && c <= 0x0060) || + (c >= 0x007B && c <= 0x007E); + } + + public static String canonicalDecomposeWithSingleQuotation(String string) { + Normalizer2 impl = Normalizer2.getNFDInstance(); + char[] src = string.toCharArray(); + int srcIndex = 0; + int srcLimit = src.length; + char[] dest = new char[src.length * 3]; //MAX_BUF_SIZE_DECOMPOSE = 3 + int destIndex = 0; + int destLimit = dest.length; + + int prevSrc; + String norm; + int reorderStartIndex, length; + char c1, c2; + int cp; + int minNoMaybe = 0x00c0; + int cc, prevCC, trailCC; + char[] p; + int pStart; + + // initialize + reorderStartIndex = 0; + prevCC = 0; + norm = null; + cp = 0; + pStart = 0; + + cc = trailCC = -1; // initialize to bogus value + c1 = 0; + for (;;) { + prevSrc=srcIndex; + //quick check (1)less than minNoMaybe (2)no decomp (3)hangual + while (srcIndex != srcLimit && + ((c1 = src[srcIndex]) < minNoMaybe || + (norm = impl.getDecomposition(cp = string.codePointAt(srcIndex))) == null || + (c1 >= '\uac00' && c1 <= '\ud7a3'))) { // Hangul Syllables + prevCC = 0; + srcIndex += (cp < 0x10000) ? 1 : 2; + } + + // copy these code units all at once + if (srcIndex != prevSrc) { + length = srcIndex - prevSrc; + if ((destIndex + length) <= destLimit) { + System.arraycopy(src,prevSrc,dest,destIndex,length); + } + + destIndex += length; + reorderStartIndex = destIndex; + } + + // end of source reached? + if (srcIndex == srcLimit) { + break; + } + + // cp already contains *src and norm32 is set for it, increment src + srcIndex += (cp < 0x10000) ? 1 : 2; + + if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + c2 = 0; + length = 1; + + if (Character.isHighSurrogate(c1) + || Character.isLowSurrogate(c1)) { + norm = null; + } + } else { + length = 2; + c2 = src[srcIndex-1]; + } + + // get the decomposition and the lead and trail cc's + if (norm == null) { + // cp does not decompose + cc = trailCC = UCharacter.getCombiningClass(cp); + p = null; + pStart = -1; + } else { + + pStart = 0; + p = norm.toCharArray(); + length = p.length; + int cpNum = norm.codePointCount(0, length); + cc= UCharacter.getCombiningClass(norm.codePointAt(0)); + trailCC= UCharacter.getCombiningClass(norm.codePointAt(cpNum-1)); + if (length == 1) { + // fastpath a single code unit from decomposition + c1 = p[pStart]; + c2 = 0; + p = null; + pStart = -1; + } + } + + if((destIndex + length * 3) >= destLimit) { // 2 SingleQuotations + // buffer overflow + char[] tmpBuf = new char[destLimit * 2]; + System.arraycopy(dest, 0, tmpBuf, 0, destIndex); + dest = tmpBuf; + destLimit = dest.length; + } + + // append the decomposition to the destination buffer, assume length>0 + { + int reorderSplit = destIndex; + if (p == null) { + // fastpath: single code point + if (needSingleQuotation(c1)) { + //if we need single quotation, no need to consider "prevCC" + //and it must NOT be a supplementary pair + dest[destIndex++] = '\''; + dest[destIndex++] = c1; + dest[destIndex++] = '\''; + trailCC = 0; + } else if(cc != 0 && cc < prevCC) { + // (c1, c2) is out of order with respect to the preceding + // text + destIndex += length; + trailCC = insertOrdered(dest, reorderStartIndex, + reorderSplit, destIndex, c1, c2, cc); + } else { + // just append (c1, c2) + dest[destIndex++] = c1; + if(c2 != 0) { + dest[destIndex++] = c2; + } + } + } else { + // general: multiple code points (ordered by themselves) + // from decomposition + if (needSingleQuotation(p[pStart])) { + dest[destIndex++] = '\''; + dest[destIndex++] = p[pStart++]; + dest[destIndex++] = '\''; + length--; + do { + dest[destIndex++] = p[pStart++]; + } while(--length > 0); + } else if (cc != 0 && cc < prevCC) { + destIndex += length; + trailCC = mergeOrdered(dest, reorderStartIndex, + reorderSplit, p, pStart, + pStart+length); + } else { + // just append the decomposition + do { + dest[destIndex++] = p[pStart++]; + } while (--length > 0); + } + } + } + prevCC = trailCC; + if(prevCC == 0) { + reorderStartIndex = destIndex; + } + } + + return new String(dest, 0, destIndex); + } /** * simpler, single-character version of mergeOrdered() - @@ -649,19 +1933,23 @@ public final class NormalizerImpl { private static int/*unsigned byte*/ insertOrdered(char[] source, int start, int current, int p, - char c, char c2, - int/*unsigned byte*/ cc) { + char c1, char c2, + int/*unsigned byte*/ cc) { int back, preBack; int r; int prevCC, trailCC=cc; - if(start<current && cc!=0) { + if (start<current && cc!=0) { // search for the insertion point where cc>=prevCC preBack=back=current; + PrevArgs prevArgs = new PrevArgs(); prevArgs.current = current; prevArgs.start = start; prevArgs.src = source; + prevArgs.c1 = c1; + prevArgs.c2 = c2; + // get the prevCC prevCC=getPrevCC(prevArgs); preBack = prevArgs.current; @@ -679,7 +1967,6 @@ public final class NormalizerImpl { back=preBack; } - // this is where we are right now with all these indicies: // [start]..[pPreBack] 0..? code points that we can ignore // [pPreBack]..[pBack] 0..1 code points with prevCC<=cc @@ -690,14 +1977,14 @@ public final class NormalizerImpl { r=p; do { source[--r]=source[--current]; - } while(back!=current); + } while (back!=current); } } - // insert (c, c2) - source[current]=c; - if(c2!=0) { - source[(current+1)]=c2; + // insert (c1, c2) + source[current] = c1; + if (c2!=0) { + source[(current+1)] = c2; } // we know the cc of the last code point @@ -732,8 +2019,7 @@ public final class NormalizerImpl { int current, char[] data, int next, - int limit, - boolean isOrdered) { + int limit) { int r; int /*unsigned byte*/ cc, trailCC=0; boolean adjacent; @@ -744,7 +2030,7 @@ public final class NormalizerImpl { ncArgs.next = next; ncArgs.limit = limit; - if(start!=current || !isOrdered) { + if(start!=current) { while(ncArgs.next<ncArgs.limit) { cc=getNextCC(ncArgs); @@ -754,20 +2040,16 @@ public final class NormalizerImpl { if(adjacent) { current=ncArgs.next; } else { - data[current++]=ncArgs.c; + data[current++]=ncArgs.c1; if(ncArgs.c2!=0) { data[current++]=ncArgs.c2; } } - if(isOrdered) { - break; - } else { - start=current; - } + break; } else { r=current+(ncArgs.c2==0 ? 1 : 2); trailCC=insertOrdered(source,start, current, r, - ncArgs.c, ncArgs.c2, cc); + ncArgs.c1, ncArgs.c2, cc); current=r; } } @@ -792,1945 +2074,82 @@ public final class NormalizerImpl { } } - private static int /*unsigned byte*/ mergeOrdered(char[] source, - int start, - int current, - char[] data, - final int next, - final int limit) { - return mergeOrdered(source,start,current,data,next,limit,true); - } - public static NormalizerBase.QuickCheckResult quickCheck(char[] src, - int srcStart, - int srcLimit, - int minNoMaybe, - int qcMask, - int options, - boolean allowMaybe, - UnicodeSet nx){ - - int ccOrQCMask; - long norm32; - char c, c2; - char cc, prevCC; - long qcNorm32; - NormalizerBase.QuickCheckResult result; - ComposePartArgs args = new ComposePartArgs(); - char[] buffer ; - int start = srcStart; - - if(!isDataLoaded) { - return NormalizerBase.MAYBE; - } - // initialize - ccOrQCMask=CC_MASK|qcMask; - result=NormalizerBase.YES; - prevCC=0; - - for(;;) { - for(;;) { - if(srcStart==srcLimit) { - return result; - } else if((c=src[srcStart++])>=minNoMaybe && - (( norm32=getNorm32(c)) & ccOrQCMask)!=0) { - break; - } - prevCC=0; - } - - - // check one above-minimum, relevant code unit - if(isNorm32LeadSurrogate(norm32)) { - // c is a lead surrogate, get the real norm32 - if(srcStart!=srcLimit&& UTF16.isTrailSurrogate(c2=src[srcStart])) { - ++srcStart; - norm32=getNorm32FromSurrogatePair(norm32,c2); - } else { - norm32=0; - c2=0; - } - }else{ - c2=0; - } - if(nx_contains(nx, c, c2)) { - /* excluded: norm32==0 */ - norm32=0; - } - - // check the combining order - cc=(char)((norm32>>CC_SHIFT)&0xFF); - if(cc!=0 && cc<prevCC) { - return NormalizerBase.NO; - } - prevCC=cc; - - // check for "no" or "maybe" quick check flags - qcNorm32 = norm32 & qcMask; - if((qcNorm32& QC_ANY_NO)>=1) { - result= NormalizerBase.NO; - break; - } else if(qcNorm32!=0) { - // "maybe" can only occur for NFC and NFKC - if(allowMaybe){ - result=NormalizerBase.MAYBE; - }else{ - // normalize a section around here to see if it is really - // normalized or not - int prevStarter; - int/*unsigned*/ decompQCMask; - - decompQCMask=(qcMask<<2)&0xf; // decomposition quick check mask - - // find the previous starter - - // set prevStarter to the beginning of the current character - prevStarter=srcStart-1; - if(UTF16.isTrailSurrogate(src[prevStarter])) { - // safe because unpaired surrogates do not result - // in "maybe" - --prevStarter; - } - prevStarter=findPreviousStarter(src, start, prevStarter, - ccOrQCMask, decompQCMask, - (char)minNoMaybe); - - // find the next true starter in [src..limit[ - modifies - // src to point to the next starter - srcStart=findNextStarter(src,srcStart, srcLimit, qcMask, - decompQCMask,(char) minNoMaybe); - - //set the args for compose part - args.prevCC = prevCC; - - // decompose and recompose [prevStarter..src[ - buffer = composePart(args,prevStarter,src,srcStart,srcLimit,options,nx); - - // compare the normalized version with the original - if(0!=strCompare(buffer,0,args.length,src,prevStarter,srcStart, false)) { - result=NormalizerBase.NO; // normalization differs - break; - } - - // continue after the next starter - } - } - } - return result; - } - - - //------------------------------------------------------ - // make NFD & NFKD - //------------------------------------------------------ - - public static int decompose(char[] src,int srcStart,int srcLimit, - char[] dest,int destStart,int destLimit, - boolean compat,int[] outTrailCC, - UnicodeSet nx) { - - char[] buffer = new char[3]; - int prevSrc; - long norm32; - int ccOrQCMask, qcMask; - int reorderStartIndex, length; - char c, c2, minNoMaybe; - int/*unsigned byte*/ cc, prevCC, trailCC; - char[] p; - int pStart; - int destIndex = destStart; - int srcIndex = srcStart; - if(!compat) { - minNoMaybe=(char)indexes[INDEX_MIN_NFD_NO_MAYBE]; - qcMask=QC_NFD; - } else { - minNoMaybe=(char)indexes[INDEX_MIN_NFKD_NO_MAYBE]; - qcMask=QC_NFKD; - } - - /* initialize */ - ccOrQCMask=CC_MASK|qcMask; - reorderStartIndex=0; - prevCC=0; - norm32=0; - c=0; - pStart=0; - - cc=trailCC=-1;//initialize to bogus value - - for(;;) { - /* count code units below the minimum or with irrelevant data for - * the quick check - */ - prevSrc=srcIndex; - - while(srcIndex!=srcLimit &&((c=src[srcIndex])<minNoMaybe || - ((norm32=getNorm32(c))&ccOrQCMask)==0)){ - prevCC=0; - ++srcIndex; - } - - /* copy these code units all at once */ - if(srcIndex!=prevSrc) { - length=srcIndex-prevSrc; - if((destIndex+length)<=destLimit) { - System.arraycopy(src,prevSrc,dest,destIndex,length); - } - - destIndex+=length; - reorderStartIndex=destIndex; - } - - /* end of source reached? */ - if(srcIndex==srcLimit) { - break; - } - - /* c already contains *src and norm32 is set for it, increment src*/ - ++srcIndex; - - /* check one above-minimum, relevant code unit */ - /* - * generally, set p and length to the decomposition string - * in simple cases, p==NULL and (c, c2) will hold the length code - * units to append in all cases, set cc to the lead and trailCC to - * the trail combining class - * - * the following merge-sort of the current character into the - * preceding, canonically ordered result text will use the - * optimized insertOrdered() - * if there is only one single code point to process; - * this is indicated with p==NULL, and (c, c2) is the character to - * insert - * ((c, 0) for a BMP character and (lead surrogate, trail surrogate) - * for a supplementary character) - * otherwise, p[length] is merged in with _mergeOrdered() - */ - if(isNorm32HangulOrJamo(norm32)) { - if(nx_contains(nx, c)) { - c2=0; - p=null; - length=1; - } else { - // Hangul syllable: decompose algorithmically - p=buffer; - pStart=0; - cc=trailCC=0; - - c-=HANGUL_BASE; - - c2=(char)(c%JAMO_T_COUNT); - c/=JAMO_T_COUNT; - if(c2>0) { - buffer[2]=(char)(JAMO_T_BASE+c2); - length=3; - } else { - length=2; - } - - buffer[1]=(char)(JAMO_V_BASE+c%JAMO_V_COUNT); - buffer[0]=(char)(JAMO_L_BASE+c/JAMO_V_COUNT); - } - } else { - if(isNorm32Regular(norm32)) { - c2=0; - length=1; - } else { - // c is a lead surrogate, get the real norm32 - if(srcIndex!=srcLimit && - UTF16.isTrailSurrogate(c2=src[srcIndex])) { - ++srcIndex; - length=2; - norm32=getNorm32FromSurrogatePair(norm32, c2); - } else { - c2=0; - length=1; - norm32=0; - } - } - - /* get the decomposition and the lead and trail cc's */ - if(nx_contains(nx, c, c2)) { - /* excluded: norm32==0 */ - cc=trailCC=0; - p=null; - } else if((norm32&qcMask)==0) { - /* c does not decompose */ - cc=trailCC=(int)((UNSIGNED_BYTE_MASK) & (norm32>>CC_SHIFT)); - p=null; - pStart=-1; - } else { - DecomposeArgs arg = new DecomposeArgs(); - /* c decomposes, get everything from the variable-length - * extra data - */ - pStart=decompose(norm32, qcMask, arg); - p=extraData; - length=arg.length; - cc=arg.cc; - trailCC=arg.trailCC; - if(length==1) { - /* fastpath a single code unit from decomposition */ - c=p[pStart]; - c2=0; - p=null; - pStart=-1; - } - } - } - - /* append the decomposition to the destination buffer, assume - * length>0 - */ - if((destIndex+length)<=destLimit) { - int reorderSplit=destIndex; - if(p==null) { - /* fastpath: single code point */ - if(cc!=0 && cc<prevCC) { - /* (c, c2) is out of order with respect to the preceding - * text - */ - destIndex+=length; - trailCC=insertOrdered(dest,reorderStartIndex, - reorderSplit, destIndex, c, c2, cc); - } else { - /* just append (c, c2) */ - dest[destIndex++]=c; - if(c2!=0) { - dest[destIndex++]=c2; - } - } - } else { - /* general: multiple code points (ordered by themselves) - * from decomposition - */ - if(cc!=0 && cc<prevCC) { - /* the decomposition is out of order with respect to the - * preceding text - */ - destIndex+=length; - trailCC=mergeOrdered(dest,reorderStartIndex, - reorderSplit,p, pStart,pStart+length); - } else { - /* just append the decomposition */ - do { - dest[destIndex++]=p[pStart++]; - } while(--length>0); - } - } - } else { - /* buffer overflow */ - /* keep incrementing the destIndex for preflighting */ - destIndex+=length; - } - - prevCC=trailCC; - if(prevCC==0) { - reorderStartIndex=destIndex; - } - } - - outTrailCC[0]=prevCC; - - return destIndex - destStart; - } - - /* make NFC & NFKC ------------------------------------------------------ */ - private static final class NextCombiningArgs{ - char[] source; + private static final class PrevArgs{ + char[] src; int start; - //int limit; - char c; + int current; + char c1; char c2; - int/*unsigned*/ combiningIndex; - char /*unsigned byte*/ cc; } - /* get the composition properties of the next character */ - private static int /*unsigned*/ getNextCombining(NextCombiningArgs args, - int limit, - UnicodeSet nx) { - long/*unsigned*/ norm32; - int combineFlags; - /* get properties */ - args.c=args.source[args.start++]; - norm32=getNorm32(args.c); - - /* preset output values for most characters */ - args.c2=0; - args.combiningIndex=0; - args.cc=0; - - if((norm32&(CC_MASK|COMBINES_ANY))==0) { - return 0; - } else { - if(isNorm32Regular(norm32)) { - /* set cc etc. below */ - } else if(isNorm32HangulOrJamo(norm32)) { - /* a compatibility decomposition contained Jamos */ - args.combiningIndex=(int)((UNSIGNED_INT_MASK)&(0xfff0| - (norm32>>EXTRA_SHIFT))); - return (int)(norm32&COMBINES_ANY); - } else { - /* c is a lead surrogate, get the real norm32 */ - if(args.start!=limit && UTF16.isTrailSurrogate(args.c2= - args.source[args.start])) { - ++args.start; - norm32=getNorm32FromSurrogatePair(norm32, args.c2); - } else { - args.c2=0; - return 0; - } - } - - if(nx_contains(nx, args.c, args.c2)) { - return 0; /* excluded: norm32==0 */ - } - - args.cc= (char)((norm32>>CC_SHIFT)&0xff); - - combineFlags=(int)(norm32&COMBINES_ANY); - if(combineFlags!=0) { - int index = getExtraDataIndex(norm32); - args.combiningIndex=index>0 ? extraData[(index-1)] :0; - } - - return combineFlags; - } - } - - /* - * given a composition-result starter (c, c2) - which means its cc==0, - * it combines forward, it has extra data, its norm32!=0, - * it is not a Hangul or Jamo, - * get just its combineFwdIndex - * - * norm32(c) is special if and only if c2!=0 - */ - private static int/*unsigned*/ getCombiningIndexFromStarter(char c,char c2){ - long/*unsigned*/ norm32; - - norm32=getNorm32(c); - if(c2!=0) { - norm32=getNorm32FromSurrogatePair(norm32, c2); - } - return extraData[(getExtraDataIndex(norm32)-1)]; - } - - /* - * Find the recomposition result for - * a forward-combining character - * (specified with a pointer to its part of the combiningTable[]) - * and a backward-combining character - * (specified with its combineBackIndex). - * - * If these two characters combine, then set (value, value2) - * with the code unit(s) of the composition character. - * - * Return value: - * 0 do not combine - * 1 combine - * >1 combine, and the composition is a forward-combining starter - * - * See unormimp.h for a description of the composition table format. - */ - private static int/*unsigned*/ combine(char[]table,int tableStart, - int/*unsinged*/ combineBackIndex, - int[] outValues) { - int/*unsigned*/ key; - int value,value2; - - if(outValues.length<2){ - throw new IllegalArgumentException(); - } - - /* search in the starter's composition table */ - for(;;) { - key=table[tableStart++]; - if(key>=combineBackIndex) { - break; - } - tableStart+= ((table[tableStart]&0x8000) != 0)? 2 : 1; - } - - /* mask off bit 15, the last-entry-in-the-list flag */ - if((key&0x7fff)==combineBackIndex) { - /* found! combine! */ - value=table[tableStart]; - - /* is the composition a starter that combines forward? */ - key=(int)((UNSIGNED_INT_MASK)&((value&0x2000)+1)); - - /* get the composition result code point from the variable-length - * result value - */ - if((value&0x8000) != 0) { - if((value&0x4000) != 0) { - /* surrogate pair composition result */ - value=(int)((UNSIGNED_INT_MASK)&((value&0x3ff)|0xd800)); - value2=table[tableStart+1]; - } else { - /* BMP composition result U+2000..U+ffff */ - value=table[tableStart+1]; - value2=0; - } - } else { - /* BMP composition result U+0000..U+1fff */ - value&=0x1fff; - value2=0; - } - outValues[0]=value; - outValues[1]=value2; - return key; - } else { - /* not found */ - return 0; - } - } - - - private static final class RecomposeArgs{ + private static final class NextCCArgs{ char[] source; - int start; + int next; int limit; - } - /* - * recompose the characters in [p..limit[ - * (which is in NFD - decomposed and canonically ordered), - * adjust limit, and return the trailing cc - * - * since for NFKC we may get Jamos in decompositions, we need to - * recompose those too - * - * note that recomposition never lengthens the text: - * any character consists of either one or two code units; - * a composition may contain at most one more code unit than the original - * starter, while the combining mark that is removed has at least one code - * unit - */ - private static char/*unsigned byte*/ recompose(RecomposeArgs args, int options, UnicodeSet nx) { - int remove, q, r; - int /*unsigned*/ combineFlags; - int /*unsigned*/ combineFwdIndex, combineBackIndex; - int /*unsigned*/ result, value=0, value2=0; - int /*unsigned byte*/ prevCC; - boolean starterIsSupplementary; - int starter; - int[] outValues = new int[2]; - starter=-1; /* no starter */ - combineFwdIndex=0; /* will not be used until starter!=NULL */ - starterIsSupplementary=false; /* will not be used until starter!=NULL */ - prevCC=0; - - NextCombiningArgs ncArg = new NextCombiningArgs(); - ncArg.source = args.source; - - ncArg.cc =0; - ncArg.c2 =0; - - for(;;) { - ncArg.start = args.start; - combineFlags=getNextCombining(ncArg,args.limit,nx); - combineBackIndex=ncArg.combiningIndex; - args.start = ncArg.start; - - if(((combineFlags&COMBINES_BACK)!=0) && starter!=-1) { - if((combineBackIndex&0x8000)!=0) { - /* c is a Jamo V/T, see if we can compose it with the - * previous character - */ - /* for the PRI #29 fix, check that there is no intervening combining mark */ - if((options&BEFORE_PRI_29)!=0 || prevCC==0) { - remove=-1; /* NULL while no Hangul composition */ - combineFlags=0; - ncArg.c2=args.source[starter]; - if(combineBackIndex==0xfff2) { - /* Jamo V, compose with previous Jamo L and following - * Jamo T - */ - ncArg.c2=(char)(ncArg.c2-JAMO_L_BASE); - if(ncArg.c2<JAMO_L_COUNT) { - remove=args.start-1; - ncArg.c=(char)(HANGUL_BASE+(ncArg.c2*JAMO_V_COUNT+ - (ncArg.c-JAMO_V_BASE))*JAMO_T_COUNT); - if(args.start!=args.limit && - (ncArg.c2=(char)(args.source[args.start] - -JAMO_T_BASE))<JAMO_T_COUNT) { - ++args.start; - ncArg.c+=ncArg.c2; - } else { - /* the result is an LV syllable, which is a starter (unlike LVT) */ - combineFlags=COMBINES_FWD; - } - if(!nx_contains(nx, ncArg.c)) { - args.source[starter]=ncArg.c; - } else { - /* excluded */ - if(!isHangulWithoutJamoT(ncArg.c)) { - --args.start; /* undo the ++args.start from reading the Jamo T */ - } - /* c is modified but not used any more -- c=*(p-1); -- re-read the Jamo V/T */ - remove=args.start; - } - } - - /* - * Normally, the following can not occur: - * Since the input is in NFD, there are no Hangul LV syllables that - * a Jamo T could combine with. - * All Jamo Ts are combined above when handling Jamo Vs. - * - * However, before the PRI #29 fix, this can occur due to - * an intervening combining mark between the Hangul LV and the Jamo T. - */ - } else { - /* Jamo T, compose with previous Hangul that does not have a Jamo T */ - if(isHangulWithoutJamoT(ncArg.c2)) { - ncArg.c2+=ncArg.c-JAMO_T_BASE; - if(!nx_contains(nx, ncArg.c2)) { - remove=args.start-1; - args.source[starter]=ncArg.c2; - } - } - } - - if(remove!=-1) { - /* remove the Jamo(s) */ - q=remove; - r=args.start; - while(r<args.limit) { - args.source[q++]=args.source[r++]; - } - args.start=remove; - args.limit=q; - } - - ncArg.c2=0; /* c2 held *starter temporarily */ - - if(combineFlags!=0) { - /* - * not starter=NULL because the composition is a Hangul LV syllable - * and might combine once more (but only before the PRI #29 fix) - */ - - /* done? */ - if(args.start==args.limit) { - return (char)prevCC; - } - - /* the composition is a Hangul LV syllable which is a starter that combines forward */ - combineFwdIndex=0xfff0; - - /* we combined; continue with looking for compositions */ - continue; - } - } - - /* - * now: cc==0 and the combining index does not include - * "forward" -> the rest of the loop body will reset starter - * to NULL; technically, a composed Hangul syllable is a - * starter, but it does not combine forward now that we have - * consumed all eligible Jamos; for Jamo V/T, combineFlags - * does not contain _NORM_COMBINES_FWD - */ - - } else if( - /* the starter is not a Hangul LV or Jamo V/T and */ - !((combineFwdIndex&0x8000)!=0) && - /* the combining mark is not blocked and */ - ((options&BEFORE_PRI_29)!=0 ? - (prevCC!=ncArg.cc || prevCC==0) : - (prevCC<ncArg.cc || prevCC==0)) && - /* the starter and the combining mark (c, c2) do combine */ - 0!=(result=combine(combiningTable,combineFwdIndex, - combineBackIndex, outValues)) && - /* the composition result is not excluded */ - !nx_contains(nx, (char)value, (char)value2) - ) { - value=outValues[0]; - value2=outValues[1]; - /* replace the starter with the composition, remove the - * combining mark - */ - remove= ncArg.c2==0 ? args.start-1 : args.start-2; /* index to the combining mark */ - - /* replace the starter with the composition */ - args.source[starter]=(char)value; - if(starterIsSupplementary) { - if(value2!=0) { - /* both are supplementary */ - args.source[starter+1]=(char)value2; - } else { - /* the composition is shorter than the starter, - * move the intermediate characters forward one */ - starterIsSupplementary=false; - q=starter+1; - r=q+1; - while(r<remove) { - args.source[q++]=args.source[r++]; - } - --remove; - } - } else if(value2!=0) { // for U+1109A, U+1109C, and U+110AB - starterIsSupplementary=true; - args.source[starter+1]=(char)value2; - /* } else { both are on the BMP, nothing more to do */ - } - - /* remove the combining mark by moving the following text - * over it */ - if(remove<args.start) { - q=remove; - r=args.start; - while(r<args.limit) { - args.source[q++]=args.source[r++]; - } - args.start=remove; - args.limit=q; - } - - /* keep prevCC because we removed the combining mark */ - - /* done? */ - if(args.start==args.limit) { - return (char)prevCC; - } - - /* is the composition a starter that combines forward? */ - if(result>1) { - combineFwdIndex=getCombiningIndexFromStarter((char)value, - (char)value2); - } else { - starter=-1; - } - - /* we combined; continue with looking for compositions */ - continue; - } - } - - /* no combination this time */ - prevCC=ncArg.cc; - if(args.start==args.limit) { - return (char)prevCC; - } - - /* if (c, c2) did not combine, then check if it is a starter */ - if(ncArg.cc==0) { - /* found a new starter; combineFlags==0 if (c, c2) is excluded */ - if((combineFlags&COMBINES_FWD)!=0) { - /* it may combine with something, prepare for it */ - if(ncArg.c2==0) { - starterIsSupplementary=false; - starter=args.start-1; - } else { - starterIsSupplementary=false; - starter=args.start-2; - } - combineFwdIndex=combineBackIndex; - } else { - /* it will not combine with anything */ - starter=-1; - } - } else if((options&OPTIONS_COMPOSE_CONTIGUOUS)!=0) { - /* FCC: no discontiguous compositions; any intervening character blocks */ - starter=-1; - } - } + char c1; + char c2; } - // find the last true starter between src[start]....src[current] going - // backwards and return its index - private static int findPreviousStarter(char[]src, int srcStart, int current, - int/*unsigned*/ ccOrQCMask, - int/*unsigned*/ decompQCMask, - char minNoMaybe) { - long norm32; - PrevArgs args = new PrevArgs(); - args.src = src; - args.start = srcStart; - args.current = current; + private static int /*unsigned*/ getPrevCC(PrevArgs args) { + args.c1=args.src[--args.current]; + args.c2=0; - while(args.start<args.current) { - norm32= getPrevNorm32(args, minNoMaybe, ccOrQCMask|decompQCMask); - if(isTrueStarter(norm32, ccOrQCMask, decompQCMask)) { - break; - } - } - return args.current; - } - - /* find the first true starter in [src..limit[ and return the - * pointer to it - */ - private static int/*index*/ findNextStarter(char[] src,int start,int limit, - int/*unsigned*/ qcMask, - int/*unsigned*/ decompQCMask, - char minNoMaybe) { - int p; - long/*unsigned*/ norm32; - int ccOrQCMask; - char c, c2; - - ccOrQCMask=CC_MASK|qcMask; - - DecomposeArgs decompArgs = new DecomposeArgs(); - - for(;;) { - if(start==limit) { - break; /* end of string */ - } - c=src[start]; - if(c<minNoMaybe) { - break; /* catches NUL terminater, too */ - } - - norm32=getNorm32(c); - if((norm32&ccOrQCMask)==0) { - break; /* true starter */ - } - - if(isNorm32LeadSurrogate(norm32)) { - /* c is a lead surrogate, get the real norm32 */ - if((start+1)==limit || - !UTF16.isTrailSurrogate(c2=(src[start+1]))){ - /* unmatched first surrogate: counts as a true starter */ - break; - } - norm32=getNorm32FromSurrogatePair(norm32, c2); - - if((norm32&ccOrQCMask)==0) { - break; /* true starter */ - } - } else { - c2=0; - } - - /* (c, c2) is not a true starter but its decomposition may be */ - if((norm32&decompQCMask)!=0) { - /* (c, c2) decomposes, get everything from the variable-length - * extra data */ - p=decompose(norm32, decompQCMask, decompArgs); - - /* get the first character's norm32 to check if it is a true - * starter */ - if(decompArgs.cc==0 && (getNorm32(extraData,p, qcMask)&qcMask)==0) { - break; /* true starter */ - } - } - - start+= c2==0 ? 1 : 2; /* not a true starter, continue */ - } - - return start; - } - - - private static final class ComposePartArgs{ - int prevCC; - int length; /* length of decomposed part */ - } - - /* decompose and recompose [prevStarter..src[ */ - private static char[] composePart(ComposePartArgs args, - int prevStarter, - char[] src, int start, int limit, - int options, - UnicodeSet nx) { - int recomposeLimit; - boolean compat =((options&OPTIONS_COMPAT)!=0); - - /* decompose [prevStarter..src[ */ - int[] outTrailCC = new int[1]; - char[] buffer = new char[(limit-prevStarter)*MAX_BUFFER_SIZE]; - - for(;;){ - args.length=decompose(src,prevStarter,(start), - buffer,0,buffer.length, - compat,outTrailCC,nx); - if(args.length<=buffer.length){ - break; - }else{ - buffer = new char[args.length]; - } - } - - /* recompose the decomposition */ - recomposeLimit=args.length; - - if(args.length>=2) { - RecomposeArgs rcArgs = new RecomposeArgs(); - rcArgs.source = buffer; - rcArgs.start = 0; - rcArgs.limit = recomposeLimit; - args.prevCC=recompose(rcArgs, options, nx); - recomposeLimit = rcArgs.limit; - } - - /* return with a pointer to the recomposition and its length */ - args.length=recomposeLimit; - return buffer; - } - - private static boolean composeHangul(char prev, char c, - long/*unsigned*/ norm32, - char[] src,int[] srcIndex, int limit, - boolean compat, - char[] dest,int destIndex, - UnicodeSet nx) { - int start=srcIndex[0]; - if(isJamoVTNorm32JamoV(norm32)) { - /* c is a Jamo V, compose with previous Jamo L and - * following Jamo T */ - prev=(char)(prev-JAMO_L_BASE); - if(prev<JAMO_L_COUNT) { - c=(char)(HANGUL_BASE+(prev*JAMO_V_COUNT+ - (c-JAMO_V_BASE))*JAMO_T_COUNT); - - /* check if the next character is a Jamo T (normal or - * compatibility) */ - if(start!=limit) { - char next, t; - - next=src[start]; - if((t=(char)(next-JAMO_T_BASE))<JAMO_T_COUNT) { - /* normal Jamo T */ - ++start; - c+=t; - } else if(compat) { - /* if NFKC, then check for compatibility Jamo T - * (BMP only) */ - norm32=getNorm32(next); - if(isNorm32Regular(norm32) && ((norm32&QC_NFKD)!=0)) { - int p /*index into extra data array*/; - DecomposeArgs dcArgs = new DecomposeArgs(); - p=decompose(norm32, QC_NFKD, dcArgs); - if(dcArgs.length==1 && - (t=(char)(extraData[p]-JAMO_T_BASE)) - <JAMO_T_COUNT) { - /* compatibility Jamo T */ - ++start; - c+=t; - } - } - } - } - if(nx_contains(nx, c)) { - if(!isHangulWithoutJamoT(c)) { - --start; /* undo ++start from reading the Jamo T */ - } - return false; - } - dest[destIndex]=c; - srcIndex[0]=start; - return true; - } - } else if(isHangulWithoutJamoT(prev)) { - /* c is a Jamo T, compose with previous Hangul LV that does not - * contain a Jamo T */ - c=(char)(prev+(c-JAMO_T_BASE)); - if(nx_contains(nx, c)) { - return false; - } - dest[destIndex]=c; - srcIndex[0]=start; - return true; - } - return false; - } - /* - public static int compose(char[] src, char[] dest,boolean compat, UnicodeSet nx){ - return compose(src,0,src.length,dest,0,dest.length,compat, nx); - } - */ - - public static int compose(char[] src, int srcStart, int srcLimit, - char[] dest,int destStart,int destLimit, - int options,UnicodeSet nx) { - - int prevSrc, prevStarter; - long/*unsigned*/ norm32; - int ccOrQCMask, qcMask; - int reorderStartIndex, length; - char c, c2, minNoMaybe; - int/*unsigned byte*/ cc, prevCC; - int[] ioIndex = new int[1]; - int destIndex = destStart; - int srcIndex = srcStart; - - if((options&OPTIONS_COMPAT)!=0) { - minNoMaybe=(char)indexes[INDEX_MIN_NFKC_NO_MAYBE]; - qcMask=QC_NFKC; + if (args.c1 < MIN_CCC_LCCC_CP) { + return 0; + } else if (UTF16.isLeadSurrogate(args.c1)) { + /* unpaired first surrogate */ + return 0; + } else if (!UTF16.isTrailSurrogate(args.c1)) { + return UCharacter.getCombiningClass(args.c1); + } else if (args.current!=args.start && + UTF16.isLeadSurrogate(args.c2=args.src[args.current-1])) { + --args.current; + return UCharacter.getCombiningClass(Character.toCodePoint(args.c2, args.c1)); } else { - minNoMaybe=(char)indexes[INDEX_MIN_NFC_NO_MAYBE]; - qcMask=QC_NFC; + /* unpaired second surrogate */ + args.c2=0; + return 0; } - - /* - * prevStarter points to the last character before the current one - * that is a "true" starter with cc==0 and quick check "yes". - * - * prevStarter will be used instead of looking for a true starter - * while incrementally decomposing [prevStarter..prevSrc[ - * in _composePart(). Having a good prevStarter allows to just decompose - * the entire [prevStarter..prevSrc[. - * - * When _composePart() backs out from prevSrc back to prevStarter, - * then it also backs out destIndex by the same amount. - * Therefore, at all times, the (prevSrc-prevStarter) source units - * must correspond 1:1 to destination units counted with destIndex, - * except for reordering. - * This is true for the qc "yes" characters copied in the fast loop, - * and for pure reordering. - * prevStarter must be set forward to src when this is not true: - * In _composePart() and after composing a Hangul syllable. - * - * This mechanism relies on the assumption that the decomposition of a - * true starter also begins with a true starter. gennorm/store.c checks - * for this. - */ - prevStarter=srcIndex; - - ccOrQCMask=CC_MASK|qcMask; - /*destIndex=*/reorderStartIndex=0;/* ####TODO#### check this **/ - prevCC=0; - - /* avoid compiler warnings */ - norm32=0; - c=0; - - for(;;) { - /* count code units below the minimum or with irrelevant data for - * the quick check */ - prevSrc=srcIndex; - - while(srcIndex!=srcLimit && ((c=src[srcIndex])<minNoMaybe || - ((norm32=getNorm32(c))&ccOrQCMask)==0)) { - prevCC=0; - ++srcIndex; - } - - - /* copy these code units all at once */ - if(srcIndex!=prevSrc) { - length=srcIndex-prevSrc; - if((destIndex+length)<=destLimit) { - System.arraycopy(src,prevSrc,dest,destIndex,length); - } - destIndex+=length; - reorderStartIndex=destIndex; - - /* set prevStarter to the last character in the quick check - * loop */ - prevStarter=srcIndex-1; - if(UTF16.isTrailSurrogate(src[prevStarter]) && - prevSrc<prevStarter && - UTF16.isLeadSurrogate(src[(prevStarter-1)])) { - --prevStarter; - } - - prevSrc=srcIndex; - } - - /* end of source reached? */ - if(srcIndex==srcLimit) { - break; - } - - /* c already contains *src and norm32 is set for it, increment src*/ - ++srcIndex; - - /* - * source buffer pointers: - * - * all done quick check current char not yet - * "yes" but (c, c2) processed - * may combine - * forward - * [-------------[-------------[-------------[-------------[ - * | | | | | - * start prevStarter prevSrc src limit - * - * - * destination buffer pointers and indexes: - * - * all done might take not filled yet - * characters for - * reordering - * [-------------[-------------[-------------[ - * | | | | - * dest reorderStartIndex destIndex destCapacity - */ - - /* check one above-minimum, relevant code unit */ - /* - * norm32 is for c=*(src-1), and the quick check flag is "no" or - * "maybe", and/or cc!=0 - * check for Jamo V/T, then for surrogates and regular characters - * c is not a Hangul syllable or Jamo L because - * they are not marked with no/maybe for NFC & NFKC(and their cc==0) - */ - if(isNorm32HangulOrJamo(norm32)) { - /* - * c is a Jamo V/T: - * try to compose with the previous character, Jamo V also with - * a following Jamo T, and set values here right now in case we - * just continue with the main loop - */ - prevCC=cc=0; - reorderStartIndex=destIndex; - ioIndex[0]=srcIndex; - if( - destIndex>0 && - composeHangul(src[(prevSrc-1)], c, norm32,src, ioIndex, - srcLimit, (options&OPTIONS_COMPAT)!=0, dest, - destIndex<=destLimit ? destIndex-1: 0, - nx) - ) { - srcIndex=ioIndex[0]; - prevStarter=srcIndex; - continue; - } - - srcIndex = ioIndex[0]; - - /* the Jamo V/T did not compose into a Hangul syllable, just - * append to dest */ - c2=0; - length=1; - prevStarter=prevSrc; - } else { - if(isNorm32Regular(norm32)) { - c2=0; - length=1; - } else { - /* c is a lead surrogate, get the real norm32 */ - if(srcIndex!=srcLimit && - UTF16.isTrailSurrogate(c2=src[srcIndex])) { - ++srcIndex; - length=2; - norm32=getNorm32FromSurrogatePair(norm32, c2); - } else { - /* c is an unpaired lead surrogate, nothing to do */ - c2=0; - length=1; - norm32=0; - } - } - ComposePartArgs args =new ComposePartArgs(); - - /* we are looking at the character (c, c2) at [prevSrc..src[ */ - if(nx_contains(nx, c, c2)) { - /* excluded: norm32==0 */ - cc=0; - } else if((norm32&qcMask)==0) { - cc=(int)((UNSIGNED_BYTE_MASK)&(norm32>>CC_SHIFT)); - } else { - char[] p; - - /* - * find appropriate boundaries around this character, - * decompose the source text from between the boundaries, - * and recompose it - * - * this puts the intermediate text into the side buffer because - * it might be longer than the recomposition end result, - * or the destination buffer may be too short or missing - * - * note that destIndex may be adjusted backwards to account - * for source text that passed the quick check but needed to - * take part in the recomposition - */ - int decompQCMask=(qcMask<<2)&0xf; /* decomposition quick check mask */ - /* - * find the last true starter in [prevStarter..src[ - * it is either the decomposition of the current character (at prevSrc), - * or prevStarter - */ - if(isTrueStarter(norm32, CC_MASK|qcMask, decompQCMask)) { - prevStarter=prevSrc; - } else { - /* adjust destIndex: back out what had been copied with qc "yes" */ - destIndex-=prevSrc-prevStarter; - } - - /* find the next true starter in [src..limit[ */ - srcIndex=findNextStarter(src, srcIndex,srcLimit, qcMask, - decompQCMask, minNoMaybe); - //args.prevStarter = prevStarter; - args.prevCC = prevCC; - //args.destIndex = destIndex; - args.length = length; - p=composePart(args,prevStarter,src,srcIndex,srcLimit,options,nx); - - if(p==null) { - /* an error occurred (out of memory) */ - break; - } - - prevCC = args.prevCC; - length = args.length; - - /* append the recomposed buffer contents to the destination - * buffer */ - if((destIndex+args.length)<=destLimit) { - int i=0; - while(i<args.length) { - dest[destIndex++]=p[i++]; - --length; - } - } else { - /* buffer overflow */ - /* keep incrementing the destIndex for preflighting */ - destIndex+=length; - } - - prevStarter=srcIndex; - continue; - } - } - - /* append the single code point (c, c2) to the destination buffer */ - if((destIndex+length)<=destLimit) { - if(cc!=0 && cc<prevCC) { - /* (c, c2) is out of order with respect to the preceding - * text */ - int reorderSplit= destIndex; - destIndex+=length; - prevCC=insertOrdered(dest,reorderStartIndex, reorderSplit, - destIndex, c, c2, cc); - } else { - /* just append (c, c2) */ - dest[destIndex++]=c; - if(c2!=0) { - dest[destIndex++]=c2; - } - prevCC=cc; - } - } else { - /* buffer overflow */ - /* keep incrementing the destIndex for preflighting */ - destIndex+=length; - prevCC=cc; - } - } - - return destIndex - destStart; } - public static int getCombiningClass(int c) { - long norm32; - norm32=getNorm32(c); - return (int)((norm32>>CC_SHIFT)&0xFF); - } + private static int /*unsigned byte*/ getNextCC(NextCCArgs args) { + args.c1=args.source[args.next++]; + args.c2=0; - public static boolean isFullCompositionExclusion(int c) { - if(isFormatVersion_2_1) { - int aux =AuxTrieImpl.auxTrie.getCodePointValue(c); - return (aux & AUX_COMP_EX_MASK)!=0; + if (UTF16.isTrailSurrogate(args.c1)) { + /* unpaired second surrogate */ + return 0; + } else if (!UTF16.isLeadSurrogate(args.c1)) { + return UCharacter.getCombiningClass(args.c1); + } else if (args.next!=args.limit && + UTF16.isTrailSurrogate(args.c2=args.source[args.next])){ + ++args.next; + return UCharacter.getCombiningClass(Character.toCodePoint(args.c1, args.c2)); } else { - return false; + /* unpaired first surrogate */ + args.c2=0; + return 0; } } - public static boolean isCanonSafeStart(int c) { - if(isFormatVersion_2_1) { - int aux = AuxTrieImpl.auxTrie.getCodePointValue(c); - return (aux & AUX_UNSAFE_MASK)==0; - } else { - return false; - } - } + private VersionInfo dataVersion; - /* Is c an NF<mode>-skippable code point? See unormimp.h. */ - public static boolean isNFSkippable(int c, NormalizerBase.Mode mode, long mask) { - long /*unsigned int*/ norm32; - mask = mask & UNSIGNED_INT_MASK; - char aux; + // Code point thresholds for quick check codes. + private int minDecompNoCP; + private int minCompNoMaybeCP; - /* check conditions (a)..(e), see unormimp.h */ - norm32 = getNorm32(c); + // Norm16 value thresholds for quick check combinations and types of extra data. + private int minYesNo; + private int minYesNoMappingsOnly; + private int minNoNo; + private int limitNoNo; + private int minMaybeYes; - if((norm32&mask)!=0) { - return false; /* fails (a)..(e), not skippable */ - } + private Trie2_16 normTrie; + private String maybeYesCompositions; + private String extraData; // mappings and/or compositions for yesYes, yesNo & noNo characters + private byte[] smallFCD; // [0x100] one bit per 32 BMP code points, set if any FCD!=0 + private int[] tccc180; // [0x180] tccc values for U+0000..U+017F - if(mode == NormalizerBase.NFD || mode == NormalizerBase.NFKD || mode == NormalizerBase.NONE){ - return true; /* NF*D, passed (a)..(c), is skippable */ - } - /* check conditions (a)..(e), see unormimp.h */ - - /* NF*C/FCC, passed (a)..(e) */ - if((norm32& QC_NFD)==0) { - return true; /* no canonical decomposition, is skippable */ - } - - /* check Hangul syllables algorithmically */ - if(isNorm32HangulOrJamo(norm32)) { - /* Jamo passed (a)..(e) above, must be Hangul */ - return !isHangulWithoutJamoT((char)c); /* LVT are skippable, LV are not */ - } - - /* if(mode<=UNORM_NFKC) { -- enable when implementing FCC */ - /* NF*C, test (f) flag */ - if(!isFormatVersion_2_2) { - return false; /* no (f) data, say not skippable to be safe */ - } - - - aux = AuxTrieImpl.auxTrie.getCodePointValue(c); - return (aux&AUX_NFC_SKIP_F_MASK)==0; /* TRUE=skippable if the (f) flag is not set */ - - /* } else { FCC, test fcd<=1 instead of the above } */ - } - - public static UnicodeSet addPropertyStarts(UnicodeSet set) { - int c; - - /* add the start code point of each same-value range of each trie */ - //utrie_enum(&normTrie, NULL, _enumPropertyStartsRange, set); - TrieIterator normIter = new TrieIterator(NormTrieImpl.normTrie); - RangeValueIterator.Element normResult = new RangeValueIterator.Element(); - - while(normIter.next(normResult)){ - set.add(normResult.start); - } - - //utrie_enum(&fcdTrie, NULL, _enumPropertyStartsRange, set); - TrieIterator fcdIter = new TrieIterator(FCDTrieImpl.fcdTrie); - RangeValueIterator.Element fcdResult = new RangeValueIterator.Element(); - - while(fcdIter.next(fcdResult)){ - set.add(fcdResult.start); - } - - if(isFormatVersion_2_1){ - //utrie_enum(&auxTrie, NULL, _enumPropertyStartsRange, set); - TrieIterator auxIter = new TrieIterator(AuxTrieImpl.auxTrie); - RangeValueIterator.Element auxResult = new RangeValueIterator.Element(); - while(auxIter.next(auxResult)){ - set.add(auxResult.start); - } - } - /* add Hangul LV syllables and LV+1 because of skippables */ - for(c=HANGUL_BASE; c<HANGUL_BASE+HANGUL_COUNT; c+=JAMO_T_COUNT) { - set.add(c); - set.add(c+1); - } - set.add(HANGUL_BASE+HANGUL_COUNT); /* add Hangul+1 to continue with other properties */ - return set; // for chaining - } - - /** - * Internal API, used in UCharacter.getIntPropertyValue(). - * @internal - * @param c code point - * @param modeValue numeric value compatible with Mode - * @return numeric value compatible with QuickCheck - */ - public static final int quickCheck(int c, int modeValue) { - final int qcMask[/*UNORM_MODE_COUNT*/]={ - 0, 0, QC_NFD, QC_NFKD, QC_NFC, QC_NFKC - }; - - int norm32=(int)getNorm32(c)&qcMask[modeValue]; - - if(norm32==0) { - return 1; // YES - } else if((norm32&QC_ANY_NO)!=0) { - return 0; // NO - } else /* _NORM_QC_ANY_MAYBE */ { - return 2; // MAYBE; - } - } - - private static int strCompare(char[] s1, int s1Start, int s1Limit, - char[] s2, int s2Start, int s2Limit, - boolean codePointOrder) { - - int start1, start2, limit1, limit2; - - char c1, c2; - - /* setup for fix-up */ - start1=s1Start; - start2=s2Start; - - int length1, length2; - - length1 = s1Limit - s1Start; - length2 = s2Limit - s2Start; - - int lengthResult; - - if(length1<length2) { - lengthResult=-1; - limit1=start1+length1; - } else if(length1==length2) { - lengthResult=0; - limit1=start1+length1; - } else /* length1>length2 */ { - lengthResult=1; - limit1=start1+length2; - } - - if(s1==s2) { - return lengthResult; - } - - for(;;) { - /* check pseudo-limit */ - if(s1Start==limit1) { - return lengthResult; - } - - c1=s1[s1Start]; - c2=s2[s2Start]; - if(c1!=c2) { - break; - } - ++s1Start; - ++s2Start; - } - - /* setup for fix-up */ - limit1=start1+length1; - limit2=start2+length2; - - - /* if both values are in or above the surrogate range, fix them up */ - if(c1>=0xd800 && c2>=0xd800 && codePointOrder) { - /* subtract 0x2800 from BMP code points to make them smaller than - * supplementary ones */ - if( - ( c1<=0xdbff && (s1Start+1)!=limit1 && - UTF16.isTrailSurrogate(s1[(s1Start+1)]) - ) || - ( UTF16.isTrailSurrogate(c1) && start1!=s1Start && - UTF16.isLeadSurrogate(s1[(s1Start-1)]) - ) - ) { - /* part of a surrogate pair, leave >=d800 */ - } else { - /* BMP code point - may be surrogate code point - make <d800 */ - c1-=0x2800; - } - - if( - ( c2<=0xdbff && (s2Start+1)!=limit2 && - UTF16.isTrailSurrogate(s2[(s2Start+1)]) - ) || - ( UTF16.isTrailSurrogate(c2) && start2!=s2Start && - UTF16.isLeadSurrogate(s2[(s2Start-1)]) - ) - ) { - /* part of a surrogate pair, leave >=d800 */ - } else { - /* BMP code point - may be surrogate code point - make <d800 */ - c2-=0x2800; - } - } - - /* now c1 and c2 are in UTF-32-compatible order */ - return (int)c1-(int)c2; - } - - - /* - * Status of tailored normalization - * - * This was done initially for investigation on Unicode public review issue 7 - * (http://www.unicode.org/review/). See Jitterbug 2481. - * While the UTC at meeting #94 (2003mar) did not take up the issue, this is - * a permanent feature in ICU 2.6 in support of IDNA which requires true - * Unicode 3.2 normalization. - * (NormalizationCorrections are rolled into IDNA mapping tables.) - * - * Tailored normalization as implemented here allows to "normalize less" - * than full Unicode normalization would. - * Based internally on a UnicodeSet of code points that are - * "excluded from normalization", the normalization functions leave those - * code points alone ("inert"). This means that tailored normalization - * still transforms text into a canonically equivalent form. - * It does not add decompositions to code points that do not have any or - * change decomposition results. - * - * Any function that searches for a safe boundary has not been touched, - * which means that these functions will be over-pessimistic when - * exclusions are applied. - * This should not matter because subsequent checks and normalizations - * do apply the exclusions; only a little more of the text may be processed - * than necessary under exclusions. - * - * Normalization exclusions have the following effect on excluded code points c: - * - c is not decomposed - * - c is not a composition target - * - c does not combine forward or backward for composition - * except that this is not implemented for Jamo - * - c is treated as having a combining class of 0 - */ - - /* - * Constants for the bit fields in the options bit set parameter. - * These need not be public. - * A user only needs to know the currently assigned values. - * The number and positions of reserved bits per field can remain private. - */ - private static final int OPTIONS_NX_MASK=0x1f; - private static final int OPTIONS_UNICODE_MASK=0xe0; - public static final int OPTIONS_SETS_MASK=0xff; -// private static final int OPTIONS_UNICODE_SHIFT=5; - private static final UnicodeSet[] nxCache = new UnicodeSet[OPTIONS_SETS_MASK+1]; - - /* Constants for options flags for normalization.*/ - - /** - * Options bit 0, do not decompose Hangul syllables. - * @draft ICU 2.6 - */ - private static final int NX_HANGUL = 1; - /** - * Options bit 1, do not decompose CJK compatibility characters. - * @draft ICU 2.6 - */ - private static final int NX_CJK_COMPAT=2; - /** - * Options bit 8, use buggy recomposition described in - * Unicode Public Review Issue #29 - * at http://www.unicode.org/review/resolved-pri.html#pri29 - * - * Used in IDNA implementation according to strict interpretation - * of IDNA definition based on Unicode 3.2 which predates PRI #29. - * - * See ICU4C unormimp.h - * - * @draft ICU 3.2 - */ - public static final int BEFORE_PRI_29=0x100; - - /* - * The following options are used only in some composition functions. - * They use bits 12 and up to preserve lower bits for the available options - * space in unorm_compare() - - * see documentation for UNORM_COMPARE_NORM_OPTIONS_SHIFT. - */ - - /** Options bit 12, for compatibility vs. canonical decomposition. */ - public static final int OPTIONS_COMPAT=0x1000; - /** Options bit 13, no discontiguous composition (FCC vs. NFC). */ - public static final int OPTIONS_COMPOSE_CONTIGUOUS=0x2000; - - /* normalization exclusion sets --------------------------------------------- */ - - /* - * Normalization exclusion UnicodeSets are used for tailored normalization; - * see the comment near the beginning of this file. - * - * By specifying one or several sets of code points, - * those code points become inert for normalization. - */ - private static final synchronized UnicodeSet internalGetNXHangul() { - /* internal function, does not check for incoming U_FAILURE */ - - if(nxCache[NX_HANGUL]==null) { - nxCache[NX_HANGUL]=new UnicodeSet(0xac00, 0xd7a3); - } - return nxCache[NX_HANGUL]; - } - - private static final synchronized UnicodeSet internalGetNXCJKCompat() { - /* internal function, does not check for incoming U_FAILURE */ - - if(nxCache[NX_CJK_COMPAT]==null) { - - /* build a set from [CJK Ideographs]&[has canonical decomposition] */ - UnicodeSet set, hasDecomp; - - set=new UnicodeSet("[:Ideographic:]"); - - /* start with an empty set for [has canonical decomposition] */ - hasDecomp=new UnicodeSet(); - - /* iterate over all ideographs and remember which canonically decompose */ - UnicodeSetIterator it = new UnicodeSetIterator(set); - int start, end; - long norm32; - - while(it.nextRange() && (it.codepoint != UnicodeSetIterator.IS_STRING)) { - start=it.codepoint; - end=it.codepointEnd; - while(start<=end) { - norm32 = getNorm32(start); - if((norm32 & QC_NFD)>0) { - hasDecomp.add(start); - } - ++start; - } - } - - /* hasDecomp now contains all ideographs that decompose canonically */ - nxCache[NX_CJK_COMPAT]=hasDecomp; - - } - - return nxCache[NX_CJK_COMPAT]; - } - - private static final synchronized UnicodeSet internalGetNXUnicode(int options) { - options &= OPTIONS_UNICODE_MASK; - if(options==0) { - return null; - } - - if(nxCache[options]==null) { - /* build a set with all code points that were not designated by the specified Unicode version */ - UnicodeSet set = new UnicodeSet(); - - switch(options) { - case NormalizerBase.UNICODE_3_2: - set.applyPattern("[:^Age=3.2:]"); - break; - default: - return null; - } - - nxCache[options]=set; - } - - return nxCache[options]; - } - - /* Get a decomposition exclusion set. The data must be loaded. */ - private static final synchronized UnicodeSet internalGetNX(int options) { - options&=OPTIONS_SETS_MASK; - - if(nxCache[options]==null) { - /* return basic sets */ - if(options==NX_HANGUL) { - return internalGetNXHangul(); - } - if(options==NX_CJK_COMPAT) { - return internalGetNXCJKCompat(); - } - if((options & OPTIONS_UNICODE_MASK)!=0 && (options & OPTIONS_NX_MASK)==0) { - return internalGetNXUnicode(options); - } - - /* build a set from multiple subsets */ - UnicodeSet set; - UnicodeSet other; - - set=new UnicodeSet(); - - - if((options & NX_HANGUL)!=0 && null!=(other=internalGetNXHangul())) { - set.addAll(other); - } - if((options&NX_CJK_COMPAT)!=0 && null!=(other=internalGetNXCJKCompat())) { - set.addAll(other); - } - if((options&OPTIONS_UNICODE_MASK)!=0 && null!=(other=internalGetNXUnicode(options))) { - set.addAll(other); - } - - nxCache[options]=set; - } - return nxCache[options]; - } - - public static final UnicodeSet getNX(int options) { - if((options&=OPTIONS_SETS_MASK)==0) { - /* incoming failure, or no decomposition exclusions requested */ - return null; - } else { - return internalGetNX(options); - } - } - - private static final boolean nx_contains(UnicodeSet nx, int c) { - return nx!=null && nx.contains(c); - } - - private static final boolean nx_contains(UnicodeSet nx, char c, char c2) { - return nx!=null && nx.contains(c2==0 ? c : UCharacterProperty.getRawSupplementary(c, c2)); - } - -/*****************************************************************************/ - - /** - * Get the canonical decomposition - * sherman for ComposedCharIter - */ - - public static int getDecompose(int chars[], String decomps[]) { - DecomposeArgs args = new DecomposeArgs(); - int length=0; - long norm32 = 0; - int ch = -1; - int index = 0; - int i = 0; - - while (++ch < 0x2fa1e) { //no cannoical above 0x3ffff - //TBD !!!! the hack code heres save us about 50ms for startup - //need a better solution/lookup - if (ch == 0x30ff) - ch = 0xf900; - else if (ch == 0x10000) - ch = 0x1d15e; - else if (ch == 0x1d1c1) - ch = 0x2f800; - - norm32 = NormalizerImpl.getNorm32(ch); - if((norm32 & QC_NFD)!=0 && i < chars.length) { - chars[i] = ch; - index = decompose(norm32, args); - decomps[i++] = new String(extraData,index, args.length); - } - } - return i; - } - - //------------------------------------------------------ - // special method for Collation - //------------------------------------------------------ - private static boolean needSingleQuotation(char c) { - return (c >= 0x0009 && c <= 0x000D) || - (c >= 0x0020 && c <= 0x002F) || - (c >= 0x003A && c <= 0x0040) || - (c >= 0x005B && c <= 0x0060) || - (c >= 0x007B && c <= 0x007E); - } - - public static String canonicalDecomposeWithSingleQuotation(String string) { - char[] src = string.toCharArray(); - int srcIndex = 0; - int srcLimit = src.length; - char[] dest = new char[src.length * 3]; //MAX_BUF_SIZE_DECOMPOSE = 3 - int destIndex = 0; - int destLimit = dest.length; - - char[] buffer = new char[3]; - int prevSrc; - long norm32; - int ccOrQCMask; - int qcMask = QC_NFD; - int reorderStartIndex, length; - char c, c2; - char minNoMaybe = (char)indexes[INDEX_MIN_NFD_NO_MAYBE]; - int cc, prevCC, trailCC; - char[] p; - int pStart; - - - // initialize - ccOrQCMask = CC_MASK | qcMask; - reorderStartIndex = 0; - prevCC = 0; - norm32 = 0; - c = 0; - pStart = 0; - - cc = trailCC = -1; // initialize to bogus value - for(;;) { - prevSrc=srcIndex; - //quick check (1)less than minNoMaybe (2)no decomp (3)hangual - while (srcIndex != srcLimit && - (( c = src[srcIndex]) < minNoMaybe || - ((norm32 = getNorm32(c)) & ccOrQCMask) == 0 || - ( c >= '\uac00' && c <= '\ud7a3'))){ - - prevCC = 0; - ++srcIndex; - } - - // copy these code units all at once - if (srcIndex != prevSrc) { - length = srcIndex - prevSrc; - if ((destIndex + length) <= destLimit) { - System.arraycopy(src,prevSrc,dest,destIndex,length); - } - - destIndex += length; - reorderStartIndex = destIndex; - } - - // end of source reached? - if(srcIndex == srcLimit) { - break; - } - // c already contains *src and norm32 is set for it, increment src - ++srcIndex; - - if(isNorm32Regular(norm32)) { - c2 = 0; - length = 1; - } else { - // c is a lead surrogate, get the real norm32 - if(srcIndex != srcLimit && - Character.isLowSurrogate(c2 = src[srcIndex])) { - ++srcIndex; - length = 2; - norm32 = getNorm32FromSurrogatePair(norm32, c2); - } else { - c2 = 0; - length = 1; - norm32 = 0; - } - } - - // get the decomposition and the lead and trail cc's - if((norm32 & qcMask) == 0) { - // c does not decompose - cc = trailCC = (int)((UNSIGNED_BYTE_MASK) & (norm32 >> CC_SHIFT)); - p = null; - pStart = -1; - } else { - DecomposeArgs arg = new DecomposeArgs(); - // c decomposes, get everything from the variable-length - // extra data - pStart = decompose(norm32, qcMask, arg); - p = extraData; - length = arg.length; - cc = arg.cc; - trailCC = arg.trailCC; - if(length == 1) { - // fastpath a single code unit from decomposition - c = p[pStart]; - c2 = 0; - p = null; - pStart = -1; - } - } - - if((destIndex + length * 3) >= destLimit) { // 2 SingleQuotations - // buffer overflow - char[] tmpBuf = new char[destLimit * 2]; - System.arraycopy(dest, 0, tmpBuf, 0, destIndex); - dest = tmpBuf; - destLimit = dest.length; - } - // append the decomposition to the destination buffer, assume length>0 - { - int reorderSplit = destIndex; - if(p == null) { - // fastpath: single code point - if (needSingleQuotation(c)) { - //if we need single quotation, no need to consider "prevCC" - //and it must NOT be a supplementary pair - dest[destIndex++] = '\''; - dest[destIndex++] = c; - dest[destIndex++] = '\''; - trailCC = 0; - } else if(cc != 0 && cc < prevCC) { - // (c, c2) is out of order with respect to the preceding - // text - destIndex += length; - trailCC = insertOrdered(dest,reorderStartIndex, - reorderSplit, destIndex, c, c2, cc); - } else { - // just append (c, c2) - dest[destIndex++] = c; - if(c2 != 0) { - dest[destIndex++] = c2; - } - } - } else { - // general: multiple code points (ordered by themselves) - // from decomposition - if (needSingleQuotation(p[pStart])) { - dest[destIndex++] = '\''; - dest[destIndex++] = p[pStart++]; - dest[destIndex++] = '\''; - length--; - do { - dest[destIndex++] = p[pStart++]; - } while(--length > 0); - } else - if(cc != 0 && cc < prevCC) { - destIndex += length; - trailCC = mergeOrdered(dest,reorderStartIndex, - reorderSplit,p, pStart,pStart+length); - } else { - // just append the decomposition - do { - dest[destIndex++] = p[pStart++]; - } while(--length > 0); - } - } - } - prevCC = trailCC; - if(prevCC == 0) { - reorderStartIndex = destIndex; - } - } - return new String(dest, 0, destIndex); - } - - //------------------------------------------------------ - // mapping method for IDNA/StringPrep - //------------------------------------------------------ - - /* - * Normalization using NormalizerBase.UNICODE_3_2 option supports Unicode - * 3.2 normalization with Corrigendum 4 corrections. However, normalization - * without the corrections is necessary for IDNA/StringPrep support. - * This method is called when NormalizerBase.UNICODE_3_2_0_ORIGINAL option - * (= sun.text.Normalizer.UNICODE_3_2) is used and normalizes five - * characters in Corrigendum 4 before normalization in order to avoid - * incorrect normalization. - * For the Corrigendum 4 issue, refer - * http://www.unicode.org/versions/corrigendum4.html - */ - - /* - * Option used in NormalizerBase.UNICODE_3_2_0_ORIGINAL. - */ - public static final int WITHOUT_CORRIGENDUM4_CORRECTIONS=0x40000; - - private static final char[][] corrigendum4MappingTable = { - {'\uD844', '\uDF6A'}, // 0x2F868 - {'\u5F33'}, // 0x2F874 - {'\u43AB'}, // 0x2F91F - {'\u7AAE'}, // 0x2F95F - {'\u4D57'}}; // 0x2F9BF - - /* - * Removing Corrigendum 4 fix - * @return normalized text - */ - public static String convert(String str) { - if (str == null) { - return null; - } - - int ch = UCharacterIterator.DONE; - StringBuffer dest = new StringBuffer(); - UCharacterIterator iter = UCharacterIterator.getInstance(str); - - while ((ch=iter.nextCodePoint())!= UCharacterIterator.DONE){ - switch (ch) { - case 0x2F868: - dest.append(corrigendum4MappingTable[0]); - break; - case 0x2F874: - dest.append(corrigendum4MappingTable[1]); - break; - case 0x2F91F: - dest.append(corrigendum4MappingTable[2]); - break; - case 0x2F95F: - dest.append(corrigendum4MappingTable[3]); - break; - case 0x2F9BF: - dest.append(corrigendum4MappingTable[4]); - break; - default: - UTF16.append(dest,ch); - break; - } - } - - return dest.toString(); - } } diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeMatcher.java b/jdk/src/java.base/share/classes/sun/text/normalizer/OutputInt.java similarity index 53% rename from jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeMatcher.java rename to jdk/src/java.base/share/classes/sun/text/normalizer/OutputInt.java index 52808c9860f..9cd1702c4c3 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeMatcher.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/OutputInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * 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,35 +25,26 @@ /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * + * Copyright (C) 2014, International Business Machines Corporation and + * others. All Rights Reserved. ******************************************************************************* */ - package sun.text.normalizer; /** - * <code>UnicodeMatcher</code> defines a protocol for objects that can - * match a range of characters in a Replaceable string. - * @stable ICU 2.0 + * Simple struct-like class for int output parameters. + * Like <code>Output<Integer></code> but without auto-boxing. + * + * @internal but could become public + * deprecated This API is ICU internal only. */ -public interface UnicodeMatcher { +class OutputInt { /** - * The character at index {@code i}, where - * {@code i < contextStart || i >= contextLimit}, - * is ETHER. This allows explicit matching by rules and UnicodeSets - * of text outside the context. In traditional terms, this allows anchoring - * at the start and/or end. - * @stable ICU 2.0 + * The value field. + * + * @internal + * deprecated This API is ICU internal only. */ - static final char ETHER = '\uFFFF'; - + public int value; } - -//eof diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/RangeValueIterator.java b/jdk/src/java.base/share/classes/sun/text/normalizer/RangeValueIterator.java deleted file mode 100644 index 771703859fe..00000000000 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/RangeValueIterator.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. - * 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. 1996-2005 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ - -package sun.text.normalizer; - -/** - * <p>Interface for enabling iteration over sets of - * {@code <int index, int value>}, - * where index is the sorted integer index in ascending order and value, its - * associated integer value. - * <p>The result for each iteration is the consecutive range of - * {@code <int index, int value>} with the same value. Result is represented by - * {@code <start, limit, value>} where - * <ul> - * <li> start is the starting integer of the result range - * <li> limit is 1 after the maximum integer that follows start, such that - * all integers between start and (limit - 1), inclusive, have the same - * associated integer value. - * <li> value is the integer value that all integers from start to (limit - 1) - * share in common. - * </ul> - * <p> - * Hence value(start) = value(start + 1) = .... = value(start + n) = .... = - * value(limit - 1). However value(start -1) != value(start) and - * value(limit) != value(start). - * - * <p>Most implementations will be created by factory methods, such as the - * character type iterator in UCharacter.getTypeIterator. See example below. - * - * Example of use:<br> - * <pre> - * RangeValueIterator iterator = UCharacter.getTypeIterator(); - * RangeValueIterator.Element result = new RangeValueIterator.Element(); - * while (iterator.next(result)) { - * System.out.println("Codepoint \\u" + - * Integer.toHexString(result.start) + - * " to codepoint \\u" + - * Integer.toHexString(result.limit - 1) + - * " has the character type " + result.value); - * } - * </pre> - * @author synwee - * @stable ICU 2.6 - */ -public interface RangeValueIterator -{ - // public inner class --------------------------------------------- - - /** - * Return result wrapper for com.ibm.icu.util.RangeValueIterator. - * Stores the start and limit of the continous result range and the - * common value all integers between [start, limit - 1] has. - * @stable ICU 2.6 - */ - public class Element - { - // public data member --------------------------------------------- - - /** - * Starting integer of the continuous result range that has the same - * value - * @stable ICU 2.6 - */ - public int start; - /** - * (End + 1) integer of continuous result range that has the same - * value - * @stable ICU 2.6 - */ - public int limit; - /** - * Gets the common value of the continous result range - * @stable ICU 2.6 - */ - public int value; - - // public constructor -------------------------------------------- - - /** - * Empty default constructor to make javadoc happy - * @stable ICU 2.4 - */ - public Element() - { - } - } - - // public methods ------------------------------------------------- - - /** - * <p>Gets the next maximal result range with a common value and returns - * true if we are not at the end of the iteration, false otherwise.</p> - * <p>If the return boolean is a false, the contents of elements will not - * be updated.</p> - * @param element for storing the result range and value - * @return true if we are not at the end of the iteration, false otherwise. - * @see Element - * @stable ICU 2.6 - */ - public boolean next(Element element); - - /** - * Resets the iterator to the beginning of the iteration. - * @stable ICU 2.6 - */ - public void reset(); -} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/Replaceable.java b/jdk/src/java.base/share/classes/sun/text/normalizer/Replaceable.java index e05593540b8..dc18b517aad 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/Replaceable.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/Replaceable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,7 +82,7 @@ package sun.text.normalizer; * @author Alan Liu * @stable ICU 2.0 */ -public interface Replaceable { +interface Replaceable { /** * Returns the number of 16-bit code units in the text. * @return number of 16-bit code units in text @@ -99,7 +99,6 @@ public interface Replaceable { */ char charAt(int offset); - //// for StringPrep /** * Copies characters from this object into the destination * character array. The first character to be copied is at index diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/ReplaceableString.java b/jdk/src/java.base/share/classes/sun/text/normalizer/ReplaceableString.java index eb2c4399cd2..a9a74a33708 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/ReplaceableString.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/ReplaceableString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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,13 +25,8 @@ /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * + * Copyright (C) 1996-2009, International Business Machines Corporation and * + * others. All Rights Reserved. * ******************************************************************************* */ @@ -51,7 +46,7 @@ package sun.text.normalizer; * @author Alan Liu * @stable ICU 2.0 */ -public class ReplaceableString implements Replaceable { +class ReplaceableString implements Replaceable { private StringBuffer buf; @@ -64,7 +59,6 @@ public class ReplaceableString implements Replaceable { buf = new StringBuffer(str); } - //// for StringPrep /** * Construct a new object using <code>buf</code> for internal * storage. The contents of <code>buf</code> at the time of @@ -98,7 +92,6 @@ public class ReplaceableString implements Replaceable { return buf.charAt(offset); } - //// for StringPrep /** * Copies characters from this object into the destination * character array. The first character to be copied is at index @@ -118,6 +111,8 @@ public class ReplaceableString implements Replaceable { * @stable ICU 2.0 */ public void getChars(int srcStart, int srcLimit, char dst[], int dstStart) { - Utility.getChars(buf, srcStart, srcLimit, dst, dstStart); + if (srcStart != srcLimit) { + buf.getChars(srcStart, srcLimit, dst, dstStart); + } } } diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/ReplaceableUCharacterIterator.java b/jdk/src/java.base/share/classes/sun/text/normalizer/ReplaceableUCharacterIterator.java index 8227ca78124..2cfeeb776d7 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/ReplaceableUCharacterIterator.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/ReplaceableUCharacterIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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 @@ package sun.text.normalizer; * * What are first, last, and getBeginIndex doing here?!?!?! */ -public class ReplaceableUCharacterIterator extends UCharacterIterator { +class ReplaceableUCharacterIterator extends UCharacterIterator { // public constructor ------------------------------------------------------ @@ -63,7 +63,6 @@ public class ReplaceableUCharacterIterator extends UCharacterIterator { this.currentIndex = 0; } - //// for StringPrep /** * Public constructor * @param buf buffer of text on which the iterator will be based @@ -164,7 +163,6 @@ public class ReplaceableUCharacterIterator extends UCharacterIterator { this.currentIndex = currentIndex; } - //// for StringPrep public int getText(char[] fillIn, int offset){ int length = replaceable.length(); if(offset < 0 || offset + length > fillIn.length){ diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/RuleCharacterIterator.java b/jdk/src/java.base/share/classes/sun/text/normalizer/RuleCharacterIterator.java deleted file mode 100644 index a287400ed4f..00000000000 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/RuleCharacterIterator.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. - * 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. 1996-2005 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ - -/* - ********************************************************************** - * Author: Alan Liu - * Created: September 23 2003 - * Since: ICU 2.8 - ********************************************************************** - */ - -package sun.text.normalizer; - -import java.text.ParsePosition; - -/** - * An iterator that returns 32-bit code points. This class is deliberately - * <em>not</em> related to any of the JDK or ICU4J character iterator classes - * in order to minimize complexity. - * @author Alan Liu - * @since ICU 2.8 - */ -@SuppressWarnings("deprecation") -public class RuleCharacterIterator { - - // TODO: Ideas for later. (Do not implement if not needed, lest the - // code coverage numbers go down due to unused methods.) - // 1. Add a copy constructor, equals() method, clone() method. - // 2. Rather than return DONE, throw an exception if the end - // is reached -- this is an alternate usage model, probably not useful. - // 3. Return isEscaped from next(). If this happens, - // don't keep an isEscaped member variable. - - /** - * Text being iterated. - */ - private String text; - - /** - * Position of iterator. - */ - private ParsePosition pos; - - /** - * Symbol table used to parse and dereference variables. May be null. - */ - private SymbolTable sym; - - /** - * Current variable expansion, or null if none. - */ - private char[] buf; - - /** - * Position within buf[]. Meaningless if buf == null. - */ - private int bufPos; - - /** - * Flag indicating whether the last character was parsed from an escape. - */ - private boolean isEscaped; - - /** - * Value returned when there are no more characters to iterate. - */ - public static final int DONE = -1; - - /** - * Bitmask option to enable parsing of variable names. - * If {@code (options & PARSE_VARIABLES) != 0}, - * then an embedded variable will be expanded to - * its value. Variables are parsed using the SymbolTable API. - */ - public static final int PARSE_VARIABLES = 1; - - /** - * Bitmask option to enable parsing of escape sequences. - * If {@code (options & PARSE_ESCAPES) != 0}, - * then an embedded escape sequence will be expanded - * to its value. Escapes are parsed using Utility.unescapeAt(). - */ - public static final int PARSE_ESCAPES = 2; - - /** - * Bitmask option to enable skipping of whitespace. - * If {@code (options & SKIP_WHITESPACE) != 0}, - * then whitespace characters will be silently - * skipped, as if they were not present in the input. Whitespace - * characters are defined by UCharacterProperty.isRuleWhiteSpace(). - */ - public static final int SKIP_WHITESPACE = 4; - - /** - * Constructs an iterator over the given text, starting at the given - * position. - * @param text the text to be iterated - * @param sym the symbol table, or null if there is none. If sym is null, - * then variables will not be deferenced, even if the PARSE_VARIABLES - * option is set. - * @param pos upon input, the index of the next character to return. If a - * variable has been dereferenced, then pos will <em>not</em> increment as - * characters of the variable value are iterated. - */ - public RuleCharacterIterator(String text, SymbolTable sym, - ParsePosition pos) { - if (text == null || pos.getIndex() > text.length()) { - throw new IllegalArgumentException(); - } - this.text = text; - this.sym = sym; - this.pos = pos; - buf = null; - } - - /** - * Returns true if this iterator has no more characters to return. - */ - public boolean atEnd() { - return buf == null && pos.getIndex() == text.length(); - } - - /** - * Returns the next character using the given options, or DONE if there - * are no more characters, and advance the position to the next - * character. - * @param options one or more of the following options, bitwise-OR-ed - * together: PARSE_VARIABLES, PARSE_ESCAPES, SKIP_WHITESPACE. - * @return the current 32-bit code point, or DONE - */ - public int next(int options) { - int c = DONE; - isEscaped = false; - - for (;;) { - c = _current(); - _advance(UTF16.getCharCount(c)); - - if (c == SymbolTable.SYMBOL_REF && buf == null && - (options & PARSE_VARIABLES) != 0 && sym != null) { - String name = sym.parseReference(text, pos, text.length()); - // If name == null there was an isolated SYMBOL_REF; - // return it. Caller must be prepared for this. - if (name == null) { - break; - } - bufPos = 0; - buf = sym.lookup(name); - if (buf == null) { - throw new IllegalArgumentException( - "Undefined variable: " + name); - } - // Handle empty variable value - if (buf.length == 0) { - buf = null; - } - continue; - } - - if ((options & SKIP_WHITESPACE) != 0 && - UCharacterProperty.isRuleWhiteSpace(c)) { - continue; - } - - if (c == '\\' && (options & PARSE_ESCAPES) != 0) { - int offset[] = new int[] { 0 }; - c = Utility.unescapeAt(lookahead(), offset); - jumpahead(offset[0]); - isEscaped = true; - if (c < 0) { - throw new IllegalArgumentException("Invalid escape"); - } - } - - break; - } - - return c; - } - - /** - * Returns true if the last character returned by next() was - * escaped. This will only be the case if the option passed in to - * next() included PARSE_ESCAPED and the next character was an - * escape sequence. - */ - public boolean isEscaped() { - return isEscaped; - } - - /** - * Returns true if this iterator is currently within a variable expansion. - */ - public boolean inVariable() { - return buf != null; - } - - /** - * Returns an object which, when later passed to setPos(), will - * restore this iterator's position. Usage idiom: - * - * RuleCharacterIterator iterator = ...; - * Object pos = iterator.getPos(null); // allocate position object - * for (;;) { - * pos = iterator.getPos(pos); // reuse position object - * int c = iterator.next(...); - * ... - * } - * iterator.setPos(pos); - * - * @param p a position object previously returned by getPos(), - * or null. If not null, it will be updated and returned. If - * null, a new position object will be allocated and returned. - * @return a position object which may be passed to setPos(), - * either `p,' or if `p' == null, a newly-allocated object - */ - public Object getPos(Object p) { - if (p == null) { - return new Object[] {buf, new int[] {pos.getIndex(), bufPos}}; - } - Object[] a = (Object[]) p; - a[0] = buf; - int[] v = (int[]) a[1]; - v[0] = pos.getIndex(); - v[1] = bufPos; - return p; - } - - /** - * Restores this iterator to the position it had when getPos() - * returned the given object. - * @param p a position object previously returned by getPos() - */ - public void setPos(Object p) { - Object[] a = (Object[]) p; - buf = (char[]) a[0]; - int[] v = (int[]) a[1]; - pos.setIndex(v[0]); - bufPos = v[1]; - } - - /** - * Skips ahead past any ignored characters, as indicated by the given - * options. This is useful in conjunction with the lookahead() method. - * - * Currently, this only has an effect for SKIP_WHITESPACE. - * @param options one or more of the following options, bitwise-OR-ed - * together: PARSE_VARIABLES, PARSE_ESCAPES, SKIP_WHITESPACE. - */ - public void skipIgnored(int options) { - if ((options & SKIP_WHITESPACE) != 0) { - for (;;) { - int a = _current(); - if (!UCharacterProperty.isRuleWhiteSpace(a)) break; - _advance(UTF16.getCharCount(a)); - } - } - } - - /** - * Returns a string containing the remainder of the characters to be - * returned by this iterator, without any option processing. If the - * iterator is currently within a variable expansion, this will only - * extend to the end of the variable expansion. This method is provided - * so that iterators may interoperate with string-based APIs. The typical - * sequence of calls is to call skipIgnored(), then call lookahead(), then - * parse the string returned by lookahead(), then call jumpahead() to - * resynchronize the iterator. - * @return a string containing the characters to be returned by future - * calls to next() - */ - public String lookahead() { - if (buf != null) { - return new String(buf, bufPos, buf.length - bufPos); - } else { - return text.substring(pos.getIndex()); - } - } - - /** - * Advances the position by the given number of 16-bit code units. - * This is useful in conjunction with the lookahead() method. - * @param count the number of 16-bit code units to jump over - */ - public void jumpahead(int count) { - if (count < 0) { - throw new IllegalArgumentException(); - } - if (buf != null) { - bufPos += count; - if (bufPos > buf.length) { - throw new IllegalArgumentException(); - } - if (bufPos == buf.length) { - buf = null; - } - } else { - int i = pos.getIndex() + count; - pos.setIndex(i); - if (i > text.length()) { - throw new IllegalArgumentException(); - } - } - } - - /** - * Returns the current 32-bit code point without parsing escapes, parsing - * variables, or skipping whitespace. - * @return the current 32-bit code point - */ - private int _current() { - if (buf != null) { - return UTF16.charAt(buf, 0, buf.length, bufPos); - } else { - int i = pos.getIndex(); - return (i < text.length()) ? UTF16.charAt(text, i) : DONE; - } - } - - /** - * Advances the position by the given amount. - * @param count the number of 16-bit code units to advance past - */ - private void _advance(int count) { - if (buf != null) { - bufPos += count; - if (bufPos == buf.length) { - buf = null; - } - } else { - pos.setIndex(pos.getIndex() + count); - if (pos.getIndex() > text.length()) { - pos.setIndex(text.length()); - } - } - } -} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/SymbolTable.java b/jdk/src/java.base/share/classes/sun/text/normalizer/SymbolTable.java deleted file mode 100644 index 305cec72867..00000000000 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/SymbolTable.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. - * 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. 1996-2005 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ - -package sun.text.normalizer; - -import java.text.ParsePosition; - -/** - * An interface that defines both lookup protocol and parsing of - * symbolic names. - * - * <p>A symbol table maintains two kinds of mappings. The first is - * between symbolic names and their values. For example, if the - * variable with the name "start" is set to the value "alpha" - * (perhaps, though not necessarily, through an expression such as - * "$start=alpha"), then the call lookup("start") will return the - * char[] array ['a', 'l', 'p', 'h', 'a']. - * - * <p>The second kind of mapping is between character values and - * UnicodeMatcher objects. This is used by RuleBasedTransliterator, - * which uses characters in the private use area to represent objects - * such as UnicodeSets. If U+E015 is mapped to the UnicodeSet [a-z], - * then lookupMatcher(0xE015) will return the UnicodeSet [a-z]. - * - * <p>Finally, a symbol table defines parsing behavior for symbolic - * names. All symbolic names start with the SYMBOL_REF character. - * When a parser encounters this character, it calls parseReference() - * with the position immediately following the SYMBOL_REF. The symbol - * table parses the name, if there is one, and returns it. - * - * @draft ICU 2.8 - * @deprecated This is a draft API and might change in a future release of ICU. - */ -@Deprecated -public interface SymbolTable { - - /** - * The character preceding a symbol reference name. - * @draft ICU 2.8 - * @deprecated This is a draft API and might change in a future release of ICU. - */ - @Deprecated - static final char SYMBOL_REF = '$'; - - /** - * Lookup the characters associated with this string and return it. - * Return {@code null} if no such name exists. The resultant - * array may have length zero. - * @param s the symbolic name to lookup - * @return a char array containing the name's value, or null if - * there is no mapping for s. - * @draft ICU 2.8 - * @deprecated This is a draft API and might change in a future release of ICU. - */ - @Deprecated - char[] lookup(String s); - - /** - * Lookup the UnicodeMatcher associated with the given character, and - * return it. Return {@code null} if not found. - * @param ch a 32-bit code point from 0 to 0x10FFFF inclusive. - * @return the UnicodeMatcher object represented by the given - * character, or null if there is no mapping for ch. - * @draft ICU 2.8 - * @deprecated This is a draft API and might change in a future release of ICU. - */ - @Deprecated - UnicodeMatcher lookupMatcher(int ch); - - /** - * Parse a symbol reference name from the given string, starting - * at the given position. If no valid symbol reference name is - * found, return null and leave pos unchanged. That is, if the - * character at pos cannot start a name, or if pos is at or after - * text.length(), then return null. This indicates an isolated - * SYMBOL_REF character. - * @param text the text to parse for the name - * @param pos on entry, the index of the first character to parse. - * This is the character following the SYMBOL_REF character. On - * exit, the index after the last parsed character. If the parse - * failed, pos is unchanged on exit. - * @param limit the index after the last character to be parsed. - * @return the parsed name, or null if there is no valid symbolic - * name at the given position. - * @draft ICU 2.8 - * @deprecated This is a draft API and might change in a future release of ICU. - */ - @Deprecated - String parseReference(String text, ParsePosition pos, int limit); -} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/Trie.java b/jdk/src/java.base/share/classes/sun/text/normalizer/Trie.java index f90b2990bd7..7a19eba4151 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/Trie.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/Trie.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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,16 +22,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* - ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* + ****************************************************************************** + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ****************************************************************************** */ package sun.text.normalizer; @@ -135,93 +131,62 @@ public abstract class Trie unserialize(inputStream); } - /** - * Trie constructor - * @param index array to be used for index - * @param options used by the trie - * @param dataManipulate object containing the information to parse the - * trie data - */ - protected Trie(char index[], int options, DataManipulate dataManipulate) - { - m_options_ = options; - if(dataManipulate != null) { - m_dataManipulate_ = dataManipulate; - } else { - m_dataManipulate_ = new DefaultGetFoldingOffset(); - } - m_isLatin1Linear_ = (m_options_ & - HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_) != 0; - m_index_ = index; - m_dataOffset_ = m_index_.length; - } - // protected data members ------------------------------------------ /** - * Lead surrogate code points' index displacement in the index array. - * <pre>{@code - * 0x10000-0xd800=0x2800 - * 0x2800 >> INDEX_STAGE_1_SHIFT_ - * }</pre> - */ + * Lead surrogate code points' index displacement in the index array. + * <pre>{@code + * 0x10000-0xd800=0x2800 + * 0x2800 >> INDEX_STAGE_1_SHIFT_ + * }</pre> + */ protected static final int LEAD_INDEX_OFFSET_ = 0x2800 >> 5; /** - * Shift size for shifting right the input index. 1..9 - */ + * Shift size for shifting right the input index. 1..9 + */ protected static final int INDEX_STAGE_1_SHIFT_ = 5; /** - * Shift size for shifting left the index array values. - * Increases possible data size with 16-bit index values at the cost - * of compactability. - * This requires blocks of stage 2 data to be aligned by - * DATA_GRANULARITY. - * 0..INDEX_STAGE_1_SHIFT - */ + * Shift size for shifting left the index array values. + * Increases possible data size with 16-bit index values at the cost + * of compactability. + * This requires blocks of stage 2 data to be aligned by + * DATA_GRANULARITY. + * 0..INDEX_STAGE_1_SHIFT + */ protected static final int INDEX_STAGE_2_SHIFT_ = 2; /** * Number of data values in a stage 2 (data array) block. */ protected static final int DATA_BLOCK_LENGTH=1<<INDEX_STAGE_1_SHIFT_; /** - * Mask for getting the lower bits from the input index. - * DATA_BLOCK_LENGTH - 1. - */ - protected static final int INDEX_STAGE_3_MASK_ = DATA_BLOCK_LENGTH - 1; - /** Number of bits of a trail surrogate that are used in index table lookups. */ - protected static final int SURROGATE_BLOCK_BITS=10-INDEX_STAGE_1_SHIFT_; - /** - * Number of index (stage 1) entries per lead surrogate. - * Same as number of index entries for 1024 trail surrogates, - * {@code ==0x400>>INDEX_STAGE_1_SHIFT_} + * Mask for getting the lower bits from the input index. + * DATA_BLOCK_LENGTH - 1. */ - protected static final int SURROGATE_BLOCK_COUNT=(1<<SURROGATE_BLOCK_BITS); - /** Length of the BMP portion of the index (stage 1) array. */ - protected static final int BMP_INDEX_LENGTH=0x10000>>INDEX_STAGE_1_SHIFT_; + protected static final int INDEX_STAGE_3_MASK_ = DATA_BLOCK_LENGTH - 1; /** - * Surrogate mask to use when shifting offset to retrieve supplementary - * values - */ + * Surrogate mask to use when shifting offset to retrieve supplementary + * values + */ protected static final int SURROGATE_MASK_ = 0x3FF; /** - * Index or UTF16 characters - */ + * Index or UTF16 characters + */ protected char m_index_[]; /** - * Internal TrieValue which handles the parsing of the data value. - * This class is to be implemented by the user - */ + * Internal TrieValue which handles the parsing of the data value. + * This class is to be implemented by the user + */ protected DataManipulate m_dataManipulate_; /** - * Start index of the data portion of the trie. CharTrie combines - * index and data into a char array, so this is used to indicate the - * initial offset to the data portion. - * Note this index always points to the initial value. - */ + * Start index of the data portion of the trie. CharTrie combines + * index and data into a char array, so this is used to indicate the + * initial offset to the data portion. + * Note this index always points to the initial value. + */ protected int m_dataOffset_; /** - * Length of the data array - */ + * Length of the data array + */ protected int m_dataLength_; // protected methods ----------------------------------------------- @@ -234,19 +199,6 @@ public abstract class Trie */ protected abstract int getSurrogateOffset(char lead, char trail); - /** - * Gets the value at the argument index - * @param index value at index will be retrieved - * @return 32 bit value - */ - protected abstract int getValue(int index); - - /** - * Gets the default initial value - * @return 32 bit value - */ - protected abstract int getInitialValue(); - /** * Gets the offset to the data which the index ch after variable offset * points to. @@ -297,13 +249,13 @@ public abstract class Trie } /** - * Internal trie getter from a code point. - * Could be faster(?) but longer with - * {@code if((c32)<=0xd7ff) { (result)=_TRIE_GET_RAW(trie, data, 0, c32); }} - * Gets the offset to data which the codepoint points to - * @param ch codepoint - * @return offset to data - */ + * Internal trie getter from a code point. + * Could be faster(?) but longer with + * {@code if((c32)<=0xd7ff) { (result)=_TRIE_GET_RAW(trie, data, 0, c32); }} + * Gets the offset to data which the codepoint points to + * @param ch codepoint + * @return offset to data + */ protected final int getCodePointOffset(int ch) { // if ((ch >> 16) == 0) slower @@ -321,7 +273,7 @@ public abstract class Trie return getSurrogateOffset(UTF16.getLeadSurrogate(ch), (char)(ch & SURROGATE_MASK_)); } else { - // return -1 // if there is an error, in this case we return + // return -1 if there is an error, in this case we return return -1; } } @@ -342,15 +294,6 @@ public abstract class Trie } } - /** - * Determines if this is a 32 bit trie - * @return true if options specifies this is a 32 bit trie - */ - protected final boolean isIntTrie() - { - return (m_options_ & HEADER_OPTIONS_DATA_IS_32_BIT_) != 0; - } - /** * Determines if this is a 16 bit trie * @return true if this is a 16 bit trie @@ -363,8 +306,8 @@ public abstract class Trie // private data members -------------------------------------------- /** - * Latin 1 option mask - */ + * Latin 1 option mask + */ protected static final int HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_ = 0x200; /** * Constant number to authenticate the byte block @@ -378,28 +321,28 @@ public abstract class Trie protected static final int HEADER_OPTIONS_DATA_IS_32_BIT_ = 0x100; /** - * Flag indicator for Latin quick access data block - */ + * Flag indicator for Latin quick access data block + */ private boolean m_isLatin1Linear_; /** - * <p>Trie options field.</p> - * <p>options bit field:<br> - * 9 1 = Latin-1 data is stored linearly at data + DATA_BLOCK_LENGTH<br> - * 8 0 = 16-bit data, 1=32-bit data<br> - * 7..4 INDEX_STAGE_1_SHIFT // 0..INDEX_STAGE_2_SHIFT<br> - * 3..0 INDEX_STAGE_2_SHIFT // 1..9<br> - */ + * <p>Trie options field.</p> + * <p>options bit field:<br> + * 9 1 = Latin-1 data is stored linearly at data + DATA_BLOCK_LENGTH<br> + * 8 0 = 16-bit data, 1=32-bit data<br> + * 7..4 INDEX_STAGE_1_SHIFT // 0..INDEX_STAGE_2_SHIFT<br> + * 3..0 INDEX_STAGE_2_SHIFT // 1..9<br> + */ private int m_options_; // private methods --------------------------------------------------- /** - * Authenticates raw data header. - * Checking the header information, signature and options. - * @param signature This contains the options and type of a Trie - * @return true if the header is authenticated valid - */ + * Authenticates raw data header. + * Checking the header information, signature and options. + * @param signature This contains the options and type of a Trie + * @return true if the header is authenticated valid + */ private final boolean checkHeader(int signature) { // check the signature diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/Trie2.java b/jdk/src/java.base/share/classes/sun/text/normalizer/Trie2.java new file mode 100644 index 00000000000..1e8343e8b24 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/Trie2.java @@ -0,0 +1,655 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package sun.text.normalizer; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Iterator; +import java.util.NoSuchElementException; + + +/** + * This is the interface and common implementation of a Unicode Trie2. + * It is a kind of compressed table that maps from Unicode code points (0..0x10ffff) + * to 16- or 32-bit integer values. It works best when there are ranges of + * characters with the same value, which is generally the case with Unicode + * character properties. + * + * This is the second common version of a Unicode trie (hence the name Trie2). + * + */ +abstract class Trie2 implements Iterable<Trie2.Range> { + + /** + * Create a Trie2 from its serialized form. Inverse of utrie2_serialize(). + * + * Reads from the current position and leaves the buffer after the end of the trie. + * + * The serialized format is identical between ICU4C and ICU4J, so this function + * will work with serialized Trie2s from either. + * + * The actual type of the returned Trie2 will be either Trie2_16 or Trie2_32, depending + * on the width of the data. + * + * To obtain the width of the Trie2, check the actual class type of the returned Trie2. + * Or use the createFromSerialized() function of Trie2_16 or Trie2_32, which will + * return only Tries of their specific type/size. + * + * The serialized Trie2 on the stream may be in either little or big endian byte order. + * This allows using serialized Tries from ICU4C without needing to consider the + * byte order of the system that created them. + * + * @param bytes a byte buffer to the serialized form of a UTrie2. + * @return An unserialized Trie2, ready for use. + * @throws IllegalArgumentException if the stream does not contain a serialized Trie2. + * @throws IOException if a read error occurs in the buffer. + * + */ + public static Trie2 createFromSerialized(ByteBuffer bytes) throws IOException { + // From ICU4C utrie2_impl.h + // * Trie2 data structure in serialized form: + // * + // * UTrie2Header header; + // * uint16_t index[header.index2Length]; + // * uint16_t data[header.shiftedDataLength<<2]; -- or uint32_t data[...] + // * @internal + // */ + // typedef struct UTrie2Header { + // /** "Tri2" in big-endian US-ASCII (0x54726932) */ + // uint32_t signature; + + // /** + // * options bit field: + // * 15.. 4 reserved (0) + // * 3.. 0 UTrie2ValueBits valueBits + // */ + // uint16_t options; + // + // /** UTRIE2_INDEX_1_OFFSET..UTRIE2_MAX_INDEX_LENGTH */ + // uint16_t indexLength; + // + // /** (UTRIE2_DATA_START_OFFSET..UTRIE2_MAX_DATA_LENGTH)>>UTRIE2_INDEX_SHIFT */ + // uint16_t shiftedDataLength; + // + // /** Null index and data blocks, not shifted. */ + // uint16_t index2NullOffset, dataNullOffset; + // + // /** + // * First code point of the single-value range ending with U+10ffff, + // * rounded up and then shifted right by UTRIE2_SHIFT_1. + // */ + // uint16_t shiftedHighStart; + // } UTrie2Header; + + ByteOrder outerByteOrder = bytes.order(); + try { + UTrie2Header header = new UTrie2Header(); + + /* check the signature */ + header.signature = bytes.getInt(); + switch (header.signature) { + case 0x54726932: + // The buffer is already set to the trie data byte order. + break; + case 0x32697254: + // Temporarily reverse the byte order. + boolean isBigEndian = outerByteOrder == ByteOrder.BIG_ENDIAN; + bytes.order(isBigEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); + header.signature = 0x54726932; + break; + default: + throw new IllegalArgumentException("Buffer does not contain a serialized UTrie2"); + } + + header.options = bytes.getChar(); + header.indexLength = bytes.getChar(); + header.shiftedDataLength = bytes.getChar(); + header.index2NullOffset = bytes.getChar(); + header.dataNullOffset = bytes.getChar(); + header.shiftedHighStart = bytes.getChar(); + + if ((header.options & UTRIE2_OPTIONS_VALUE_BITS_MASK) != 0) { + throw new IllegalArgumentException("UTrie2 serialized format error."); + } + + Trie2 This; + This = new Trie2_16(); + This.header = header; + + /* get the length values and offsets */ + This.indexLength = header.indexLength; + This.dataLength = header.shiftedDataLength << UTRIE2_INDEX_SHIFT; + This.index2NullOffset = header.index2NullOffset; + This.dataNullOffset = header.dataNullOffset; + This.highStart = header.shiftedHighStart << UTRIE2_SHIFT_1; + This.highValueIndex = This.dataLength - UTRIE2_DATA_GRANULARITY; + This.highValueIndex += This.indexLength; + + // Allocate the Trie2 index array. If the data width is 16 bits, the array also + // includes the space for the data. + + int indexArraySize = This.indexLength; + indexArraySize += This.dataLength; + This.index = new char[indexArraySize]; + + /* Read in the index */ + int i; + for (i=0; i<This.indexLength; i++) { + This.index[i] = bytes.getChar(); + } + + /* Read in the data. 16 bit data goes in the same array as the index. + * 32 bit data goes in its own separate data array. + */ + This.data16 = This.indexLength; + for (i=0; i<This.dataLength; i++) { + This.index[This.data16 + i] = bytes.getChar(); + } + + This.data32 = null; + This.initialValue = This.index[This.dataNullOffset]; + This.errorValue = This.index[This.data16+UTRIE2_BAD_UTF8_DATA_OFFSET]; + + return This; + } finally { + bytes.order(outerByteOrder); + } + } + + /** + * Get the value for a code point as stored in the Trie2. + * + * @param codePoint the code point + * @return the value + */ + abstract public int get(int codePoint); + + /** + * Get the trie value for a UTF-16 code unit. + * + * A Trie2 stores two distinct values for input in the lead surrogate + * range, one for lead surrogates, which is the value that will be + * returned by this function, and a second value that is returned + * by Trie2.get(). + * + * For code units outside of the lead surrogate range, this function + * returns the same result as Trie2.get(). + * + * This function, together with the alternate value for lead surrogates, + * makes possible very efficient processing of UTF-16 strings without + * first converting surrogate pairs to their corresponding 32 bit code point + * values. + * + * At build-time, enumerate the contents of the Trie2 to see if there + * is non-trivial (non-initialValue) data for any of the supplementary + * code points associated with a lead surrogate. + * If so, then set a special (application-specific) value for the + * lead surrogate code _unit_, with Trie2Writable.setForLeadSurrogateCodeUnit(). + * + * At runtime, use Trie2.getFromU16SingleLead(). If there is non-trivial + * data and the code unit is a lead surrogate, then check if a trail surrogate + * follows. If so, assemble the supplementary code point and look up its value + * with Trie2.get(); otherwise reset the lead + * surrogate's value or do a code point lookup for it. + * + * If there is only trivial data for lead and trail surrogates, then processing + * can often skip them. For example, in normalization or case mapping + * all characters that do not have any mappings are simply copied as is. + * + * @param c the code point or lead surrogate value. + * @return the value + */ + abstract public int getFromU16SingleLead(char c); + + /** + * When iterating over the contents of a Trie2, Elements of this type are produced. + * The iterator will return one item for each contiguous range of codepoints having the same value. + * + * When iterating, the same Trie2EnumRange object will be reused and returned for each range. + * If you need to retain complete iteration results, clone each returned Trie2EnumRange, + * or save the range in some other way, before advancing to the next iteration step. + */ + public static class Range { + public int startCodePoint; + public int endCodePoint; // Inclusive. + public int value; + public boolean leadSurrogate; + + public boolean equals(Object other) { + if (other == null || !(other.getClass().equals(getClass()))) { + return false; + } + Range tother = (Range)other; + return this.startCodePoint == tother.startCodePoint && + this.endCodePoint == tother.endCodePoint && + this.value == tother.value && + this.leadSurrogate == tother.leadSurrogate; + } + + public int hashCode() { + int h = initHash(); + h = hashUChar32(h, startCodePoint); + h = hashUChar32(h, endCodePoint); + h = hashInt(h, value); + h = hashByte(h, leadSurrogate? 1: 0); + return h; + } + } + + /** + * Create an iterator over the value ranges in this Trie2. + * Values from the Trie2 are not remapped or filtered, but are returned as they + * are stored in the Trie2. + * + * @return an Iterator + */ + public Iterator<Range> iterator() { + return iterator(defaultValueMapper); + } + + private static ValueMapper defaultValueMapper = new ValueMapper() { + public int map(int in) { + return in; + } + }; + + /** + * Create an iterator over the value ranges from this Trie2. + * Values from the Trie2 are passed through a caller-supplied remapping function, + * and it is the remapped values that determine the ranges that + * will be produced by the iterator. + * + * + * @param mapper provides a function to remap values obtained from the Trie2. + * @return an Iterator + */ + public Iterator<Range> iterator(ValueMapper mapper) { + return new Trie2Iterator(mapper); + } + + /** + * When iterating over the contents of a Trie2, an instance of TrieValueMapper may + * be used to remap the values from the Trie2. The remapped values will be used + * both in determining the ranges of codepoints and as the value to be returned + * for each range. + * + * Example of use, with an anonymous subclass of TrieValueMapper: + * + * + * ValueMapper m = new ValueMapper() { + * int map(int in) {return in & 0x1f;}; + * } + * for (Iterator<Trie2EnumRange> iter = trie.iterator(m); i.hasNext(); ) { + * Trie2EnumRange r = i.next(); + * ... // Do something with the range r. + * } + * + */ + public interface ValueMapper { + public int map(int originalVal); + } + + //-------------------------------------------------------------------------------- + // + // Below this point are internal implementation items. No further public API. + // + //-------------------------------------------------------------------------------- + + /** + * Trie2 data structure in serialized form: + * + * UTrie2Header header; + * uint16_t index[header.index2Length]; + * uint16_t data[header.shiftedDataLength<<2]; -- or uint32_t data[...] + * + * For Java, this is read from the stream into an instance of UTrie2Header. + * (The C version just places a struct over the raw serialized data.) + * + * @internal + */ + static class UTrie2Header { + /** "Tri2" in big-endian US-ASCII (0x54726932) */ + int signature; + + /** + * options bit field (uint16_t): + * 15.. 4 reserved (0) + * 3.. 0 UTrie2ValueBits valueBits + */ + int options; + + /** UTRIE2_INDEX_1_OFFSET..UTRIE2_MAX_INDEX_LENGTH (uint16_t) */ + int indexLength; + + /** (UTRIE2_DATA_START_OFFSET..UTRIE2_MAX_DATA_LENGTH)>>UTRIE2_INDEX_SHIFT (uint16_t) */ + int shiftedDataLength; + + /** Null index and data blocks, not shifted. (uint16_t) */ + int index2NullOffset, dataNullOffset; + + /** + * First code point of the single-value range ending with U+10ffff, + * rounded up and then shifted right by UTRIE2_SHIFT_1. (uint16_t) + */ + int shiftedHighStart; + } + + // + // Data members of UTrie2. + // + UTrie2Header header; + char index[]; // Index array. Includes data for 16 bit Tries. + int data16; // Offset to data portion of the index array, if 16 bit data. + // zero if 32 bit data. + int data32[]; // NULL if 16b data is used via index + + int indexLength; + int dataLength; + int index2NullOffset; // 0xffff if there is no dedicated index-2 null block + int initialValue; + + /** Value returned for out-of-range code points and illegal UTF-8. */ + int errorValue; + + /* Start of the last range which ends at U+10ffff, and its value. */ + int highStart; + int highValueIndex; + + int dataNullOffset; + + /** + * Trie2 constants, defining shift widths, index array lengths, etc. + * + * These are needed for the runtime macros but users can treat these as + * implementation details and skip to the actual public API further below. + */ + + static final int UTRIE2_OPTIONS_VALUE_BITS_MASK=0x000f; + + + /** Shift size for getting the index-1 table offset. */ + static final int UTRIE2_SHIFT_1=6+5; + + /** Shift size for getting the index-2 table offset. */ + static final int UTRIE2_SHIFT_2=5; + + /** + * Difference between the two shift sizes, + * for getting an index-1 offset from an index-2 offset. 6=11-5 + */ + static final int UTRIE2_SHIFT_1_2=UTRIE2_SHIFT_1-UTRIE2_SHIFT_2; + + /** + * Number of index-1 entries for the BMP. 32=0x20 + * This part of the index-1 table is omitted from the serialized form. + */ + static final int UTRIE2_OMITTED_BMP_INDEX_1_LENGTH=0x10000>>UTRIE2_SHIFT_1; + + /** Number of entries in an index-2 block. 64=0x40 */ + static final int UTRIE2_INDEX_2_BLOCK_LENGTH=1<<UTRIE2_SHIFT_1_2; + + /** Mask for getting the lower bits for the in-index-2-block offset. */ + static final int UTRIE2_INDEX_2_MASK=UTRIE2_INDEX_2_BLOCK_LENGTH-1; + + /** Number of entries in a data block. 32=0x20 */ + static final int UTRIE2_DATA_BLOCK_LENGTH=1<<UTRIE2_SHIFT_2; + + /** Mask for getting the lower bits for the in-data-block offset. */ + static final int UTRIE2_DATA_MASK=UTRIE2_DATA_BLOCK_LENGTH-1; + + /** + * Shift size for shifting left the index array values. + * Increases possible data size with 16-bit index values at the cost + * of compactability. + * This requires data blocks to be aligned by UTRIE2_DATA_GRANULARITY. + */ + static final int UTRIE2_INDEX_SHIFT=2; + + /** The alignment size of a data block. Also the granularity for compaction. */ + static final int UTRIE2_DATA_GRANULARITY=1<<UTRIE2_INDEX_SHIFT; + + /** + * The part of the index-2 table for U+D800..U+DBFF stores values for + * lead surrogate code _units_ not code _points_. + * Values for lead surrogate code _points_ are indexed with this portion of the table. + * Length=32=0x20=0x400>>UTRIE2_SHIFT_2. (There are 1024=0x400 lead surrogates.) + */ + static final int UTRIE2_LSCP_INDEX_2_OFFSET=0x10000>>UTRIE2_SHIFT_2; + static final int UTRIE2_LSCP_INDEX_2_LENGTH=0x400>>UTRIE2_SHIFT_2; + + /** Count the lengths of both BMP pieces. 2080=0x820 */ + static final int UTRIE2_INDEX_2_BMP_LENGTH=UTRIE2_LSCP_INDEX_2_OFFSET+UTRIE2_LSCP_INDEX_2_LENGTH; + + /** + * The 2-byte UTF-8 version of the index-2 table follows at offset 2080=0x820. + * Length 32=0x20 for lead bytes C0..DF, regardless of UTRIE2_SHIFT_2. + */ + static final int UTRIE2_UTF8_2B_INDEX_2_OFFSET=UTRIE2_INDEX_2_BMP_LENGTH; + static final int UTRIE2_UTF8_2B_INDEX_2_LENGTH=0x800>>6; /* U+0800 is the first code point after 2-byte UTF-8 */ + + /** + * The index-1 table, only used for supplementary code points, at offset 2112=0x840. + * Variable length, for code points up to highStart, where the last single-value range starts. + * Maximum length 512=0x200=0x100000>>UTRIE2_SHIFT_1. + * (For 0x100000 supplementary code points U+10000..U+10ffff.) + * + * The part of the index-2 table for supplementary code points starts + * after this index-1 table. + * + * Both the index-1 table and the following part of the index-2 table + * are omitted completely if there is only BMP data. + */ + static final int UTRIE2_INDEX_1_OFFSET=UTRIE2_UTF8_2B_INDEX_2_OFFSET+UTRIE2_UTF8_2B_INDEX_2_LENGTH; + + /** + * The illegal-UTF-8 data block follows the ASCII block, at offset 128=0x80. + * Used with linear access for single bytes 0..0xbf for simple error handling. + * Length 64=0x40, not UTRIE2_DATA_BLOCK_LENGTH. + */ + static final int UTRIE2_BAD_UTF8_DATA_OFFSET=0x80; + + /** + * Implementation class for an iterator over a Trie2. + * + * Iteration over a Trie2 first returns all of the ranges that are indexed by code points, + * then returns the special alternate values for the lead surrogates + * + * @internal + */ + class Trie2Iterator implements Iterator<Range> { + + // The normal constructor that configures the iterator to cover the complete + // contents of the Trie2 + Trie2Iterator(ValueMapper vm) { + mapper = vm; + nextStart = 0; + limitCP = 0x110000; + doLeadSurrogates = true; + } + + /** + * The main next() function for Trie2 iterators + * + */ + public Range next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + if (nextStart >= limitCP) { + // Switch over from iterating normal code point values to + // doing the alternate lead-surrogate values. + doingCodePoints = false; + nextStart = 0xd800; + } + int endOfRange = 0; + int val = 0; + int mappedVal = 0; + + if (doingCodePoints) { + // Iteration over code point values. + val = get(nextStart); + mappedVal = mapper.map(val); + endOfRange = rangeEnd(nextStart, limitCP, val); + // Loop once for each range in the Trie2 with the same raw (unmapped) value. + // Loop continues so long as the mapped values are the same. + for (;;) { + if (endOfRange >= limitCP-1) { + break; + } + val = get(endOfRange+1); + if (mapper.map(val) != mappedVal) { + break; + } + endOfRange = rangeEnd(endOfRange+1, limitCP, val); + } + } else { + // Iteration over the alternate lead surrogate values. + val = getFromU16SingleLead((char)nextStart); + mappedVal = mapper.map(val); + endOfRange = rangeEndLS((char)nextStart); + // Loop once for each range in the Trie2 with the same raw (unmapped) value. + // Loop continues so long as the mapped values are the same. + for (;;) { + if (endOfRange >= 0xdbff) { + break; + } + val = getFromU16SingleLead((char)(endOfRange+1)); + if (mapper.map(val) != mappedVal) { + break; + } + endOfRange = rangeEndLS((char)(endOfRange+1)); + } + } + returnValue.startCodePoint = nextStart; + returnValue.endCodePoint = endOfRange; + returnValue.value = mappedVal; + returnValue.leadSurrogate = !doingCodePoints; + nextStart = endOfRange+1; + return returnValue; + } + + /** + * + */ + public boolean hasNext() { + return doingCodePoints && (doLeadSurrogates || nextStart < limitCP) || nextStart < 0xdc00; + } + + private int rangeEndLS(char startingLS) { + if (startingLS >= 0xdbff) { + return 0xdbff; + } + + int c; + int val = getFromU16SingleLead(startingLS); + for (c = startingLS+1; c <= 0x0dbff; c++) { + if (getFromU16SingleLead((char)c) != val) { + break; + } + } + return c-1; + } + + // + // Iteration State Variables + // + private ValueMapper mapper; + private Range returnValue = new Range(); + // The starting code point for the next range to be returned. + private int nextStart; + // The upper limit for the last normal range to be returned. Normally 0x110000, but + // may be lower when iterating over the code points for a single lead surrogate. + private int limitCP; + + // True while iterating over the the Trie2 values for code points. + // False while iterating over the alternate values for lead surrogates. + private boolean doingCodePoints = true; + + // True if the iterator should iterate the special values for lead surrogates in + // addition to the normal values for code points. + private boolean doLeadSurrogates = true; + } + + /** + * Find the last character in a contiguous range of characters with the + * same Trie2 value as the input character. + * + * @param c The character to begin with. + * @return The last contiguous character with the same value. + */ + int rangeEnd(int start, int limitp, int val) { + int c; + int limit = Math.min(highStart, limitp); + + for (c = start+1; c < limit; c++) { + if (get(c) != val) { + break; + } + } + if (c >= highStart) { + c = limitp; + } + return c - 1; + } + + + // + // Hashing implementation functions. FNV hash. Respected public domain algorithm. + // + private static int initHash() { + return 0x811c9DC5; // unsigned 2166136261 + } + + private static int hashByte(int h, int b) { + h = h * 16777619; + h = h ^ b; + return h; + } + + private static int hashUChar32(int h, int c) { + h = Trie2.hashByte(h, c & 255); + h = Trie2.hashByte(h, (c>>8) & 255); + h = Trie2.hashByte(h, c>>16); + return h; + } + + private static int hashInt(int h, int i) { + h = Trie2.hashByte(h, i & 255); + h = Trie2.hashByte(h, (i>>8) & 255); + h = Trie2.hashByte(h, (i>>16) & 255); + h = Trie2.hashByte(h, (i>>24) & 255); + return h; + } + +} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/Trie2_16.java b/jdk/src/java.base/share/classes/sun/text/normalizer/Trie2_16.java new file mode 100644 index 00000000000..df73ee1d11d --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/Trie2_16.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package sun.text.normalizer; + +import java.io.IOException; +import java.nio.ByteBuffer; + + +/** + * @author aheninger + * + * A read-only Trie2, holding 16 bit data values. + * + * A Trie2 is a highly optimized data structure for mapping from Unicode + * code points (values ranging from 0 to 0x10ffff) to a 16 or 32 bit value. + * + * See class Trie2 for descriptions of the API for accessing the contents of a trie. + * + * The fundamental data access methods are declared final in this class, with + * the intent that applications might gain a little extra performance, when compared + * with calling the same methods via the abstract UTrie2 base class. + */ +public final class Trie2_16 extends Trie2 { + + /** + * Internal constructor, not for general use. + */ + Trie2_16() { + } + + + /** + * Create a Trie2 from its serialized form. Inverse of utrie2_serialize(). + * The serialized format is identical between ICU4C and ICU4J, so this function + * will work with serialized Trie2s from either. + * + * The serialized Trie2 in the bytes may be in either little or big endian byte order. + * This allows using serialized Tries from ICU4C without needing to consider the + * byte order of the system that created them. + * + * @param bytes a byte buffer to the serialized form of a UTrie2. + * @return An unserialized Trie2_16, ready for use. + * @throws IllegalArgumentException if the buffer does not contain a serialized Trie2. + * @throws IOException if a read error occurs in the buffer. + * @throws ClassCastException if the bytes contain a serialized Trie2_32 + */ + public static Trie2_16 createFromSerialized(ByteBuffer bytes) throws IOException { + return (Trie2_16) Trie2.createFromSerialized(bytes); + } + + /** + * Get the value for a code point as stored in the Trie2. + * + * @param codePoint the code point + * @return the value + */ + @Override + public final int get(int codePoint) { + int value; + int ix; + + if (codePoint >= 0) { + if (codePoint < 0x0d800 || (codePoint > 0x0dbff && codePoint <= 0x0ffff)) { + // Ordinary BMP code point, excluding leading surrogates. + // BMP uses a single level lookup. BMP index starts at offset 0 in the Trie2 index. + // 16 bit data is stored in the index array itself. + ix = index[codePoint >> UTRIE2_SHIFT_2]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint <= 0xffff) { + // Lead Surrogate Code Point. A Separate index section is stored for + // lead surrogate code units and code points. + // The main index has the code unit data. + // For this function, we need the code point data. + // Note: this expression could be refactored for slightly improved efficiency, but + // surrogate code points will be so rare in practice that it's not worth it. + ix = index[UTRIE2_LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> UTRIE2_SHIFT_2)]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint < highStart) { + // Supplemental code point, use two-level lookup. + ix = (UTRIE2_INDEX_1_OFFSET - UTRIE2_OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> UTRIE2_SHIFT_1); + ix = index[ix]; + ix += (codePoint >> UTRIE2_SHIFT_2) & UTRIE2_INDEX_2_MASK; + ix = index[ix]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint <= 0x10ffff) { + value = index[highValueIndex]; + return value; + } + } + + // Fall through. The code point is outside of the legal range of 0..0x10ffff. + return errorValue; + } + + + /** + * Get a Trie2 value for a UTF-16 code unit. + * + * This function returns the same value as get() if the input + * character is outside of the lead surrogate range + * + * There are two values stored in a Trie2 for inputs in the lead + * surrogate range. This function returns the alternate value, + * while Trie2.get() returns the main value. + * + * @param codeUnit a 16 bit code unit or lead surrogate value. + * @return the value + */ + @Override + public int getFromU16SingleLead(char codeUnit) { + int value; + int ix; + + // Because the input is a 16 bit char, we can skip the tests for it being in + // the BMP range. It is. + ix = index[codeUnit >> UTRIE2_SHIFT_2]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codeUnit & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + + /** + * @return the number of bytes of the serialized trie + */ + public int getSerializedLength() { + return 16+(header.indexLength+dataLength)*2; + } +} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/TrieIterator.java b/jdk/src/java.base/share/classes/sun/text/normalizer/TrieIterator.java deleted file mode 100644 index b4f301c0f96..00000000000 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/TrieIterator.java +++ /dev/null @@ -1,547 +0,0 @@ -/* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. - * 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. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ - -package sun.text.normalizer; - -/** - * Class enabling iteration of the values in a Trie. - * <p>Result of each iteration contains the interval of codepoints that have - * the same value type and the value type itself. - * <p>The comparison of each codepoint value is done via extract(), which the - * default implementation is to return the value as it is. - * <p>Method extract() can be overwritten to perform manipulations on - * codepoint values in order to perform specialized comparison. - * <p>TrieIterator is designed to be a generic iterator for the CharTrie - * and the IntTrie, hence to accommodate both types of data, the return - * result will be in terms of int (32 bit) values. - * <p>See com.ibm.icu.text.UCharacterTypeIterator for examples of use. - * <p>Notes for porting utrie_enum from icu4c to icu4j:<br> - * Internally, icu4c's utrie_enum performs all iterations in its body. In Java - * sense, the caller will have to pass a object with a callback function - * UTrieEnumRange(const void *context, UChar32 start, UChar32 limit, - * uint32_t value) into utrie_enum. utrie_enum will then find ranges of - * codepoints with the same value as determined by - * UTrieEnumValue(const void *context, uint32_t value). for each range, - * utrie_enum calls the callback function to perform a task. In this way, - * icu4c performs the iteration within utrie_enum. - * To follow the JDK model, icu4j is slightly different from icu4c. - * Instead of requesting the caller to implement an object for a callback. - * The caller will have to implement a subclass of TrieIterator, fleshing out - * the method extract(int) (equivalent to UTrieEnumValue). Independent of icu4j, - * the caller will have to code his own iteration and flesh out the task - * (equivalent to UTrieEnumRange) to be performed in the iteration loop. - * - * <p>There are basically 3 usage scenarios for porting: - * <p>1) UTrieEnumValue is the only implemented callback then just implement a - * subclass of TrieIterator and override the extract(int) method. The - * extract(int) method is analogus to UTrieEnumValue callback. - * - * <p>2) UTrieEnumValue and UTrieEnumRange both are implemented then implement - * a subclass of TrieIterator, override the extract method and iterate, e.g.<br> - * {@code utrie_enum(&normTrie, _enumPropertyStartsValue, _enumPropertyStartsRange, - * set);}<br> - * In Java:<br> - * <pre> - * class TrieIteratorImpl extends TrieIterator{ - * public TrieIteratorImpl(Trie data){ - * super(data); - * } - * public int extract(int value){ - * // port the implementation of _enumPropertyStartsValue here - * } - * } - * .... - * TrieIterator fcdIter = new TrieIteratorImpl(fcdTrieImpl.fcdTrie); - * while(fcdIter.next(result)) { - * // port the implementation of _enumPropertyStartsRange - * } - * </pre> - * - * <p>3) UTrieEnumRange is the only implemented callback then just implement - * the while loop, when utrie_enum is called - * <pre>{@code - * // utrie_enum(&fcdTrie, NULL, _enumPropertyStartsRange, set); - * TrieIterator fcdIter = new TrieIterator(fcdTrieImpl.fcdTrie); - * while(fcdIter.next(result)){ - * set.add(result.start); - * } - * }</pre> - * - * @author synwee - * @see com.ibm.icu.impl.Trie - * @see com.ibm.icu.lang.UCharacterTypeIterator - * @since release 2.1, Jan 17 2002 - */ -public class TrieIterator implements RangeValueIterator -{ - - // public constructor --------------------------------------------- - - /** - * TrieEnumeration constructor - * @param trie to be used - * @exception IllegalArgumentException throw when argument is null. - */ - public TrieIterator(Trie trie) - { - if (trie == null) { - throw new IllegalArgumentException( - "Argument trie cannot be null"); - } - m_trie_ = trie; - // synwee: check that extract belongs to the child class - m_initialValue_ = extract(m_trie_.getInitialValue()); - reset(); - } - - // public methods ------------------------------------------------- - - /** - * <p>Returns true if we are not at the end of the iteration, false - * otherwise.</p> - * <p>The next set of codepoints with the same value type will be - * calculated during this call and returned in the arguement element.</p> - * @param element return result - * @return true if we are not at the end of the iteration, false otherwise. - * @exception NoSuchElementException - if no more elements exist. - * @see com.ibm.icu.util.RangeValueIterator.Element - */ - public final boolean next(Element element) - { - if (m_nextCodepoint_ > UCharacter.MAX_VALUE) { - return false; - } - if (m_nextCodepoint_ < UCharacter.SUPPLEMENTARY_MIN_VALUE && - calculateNextBMPElement(element)) { - return true; - } - calculateNextSupplementaryElement(element); - return true; - } - - /** - * Resets the iterator to the beginning of the iteration - */ - public final void reset() - { - m_currentCodepoint_ = 0; - m_nextCodepoint_ = 0; - m_nextIndex_ = 0; - m_nextBlock_ = m_trie_.m_index_[0] << Trie.INDEX_STAGE_2_SHIFT_; - if (m_nextBlock_ == 0) { - m_nextValue_ = m_initialValue_; - } - else { - m_nextValue_ = extract(m_trie_.getValue(m_nextBlock_)); - } - m_nextBlockIndex_ = 0; - m_nextTrailIndexOffset_ = TRAIL_SURROGATE_INDEX_BLOCK_LENGTH_; - } - - // protected methods ---------------------------------------------- - - /** - * Called by next() to extracts a 32 bit value from a trie value - * used for comparison. - * This method is to be overwritten if special manipulation is to be done - * to retrieve a relevant comparison. - * The default function is to return the value as it is. - * @param value a value from the trie - * @return extracted value - */ - protected int extract(int value) - { - return value; - } - - // private methods ------------------------------------------------ - - /** - * Set the result values - * @param element return result object - * @param start codepoint of range - * @param limit (end + 1) codepoint of range - * @param value common value of range - */ - private final void setResult(Element element, int start, int limit, - int value) - { - element.start = start; - element.limit = limit; - element.value = value; - } - - /** - * Finding the next element. - * This method is called just before returning the result of - * next(). - * We always store the next element before it is requested. - * In the case that we have to continue calculations into the - * supplementary planes, a false will be returned. - * @param element return result object - * @return true if the next range is found, false if we have to proceed to - * the supplementary range. - */ - private final boolean calculateNextBMPElement(Element element) - { - int currentBlock = m_nextBlock_; - int currentValue = m_nextValue_; - m_currentCodepoint_ = m_nextCodepoint_; - m_nextCodepoint_ ++; - m_nextBlockIndex_ ++; - if (!checkBlockDetail(currentValue)) { - setResult(element, m_currentCodepoint_, m_nextCodepoint_, - currentValue); - return true; - } - // synwee check that next block index == 0 here - // enumerate BMP - the main loop enumerates data blocks - while (m_nextCodepoint_ < UCharacter.SUPPLEMENTARY_MIN_VALUE) { - m_nextIndex_ ++; - // because of the way the character is split to form the index - // the lead surrogate and trail surrogate can not be in the - // mid of a block - if (m_nextCodepoint_ == LEAD_SURROGATE_MIN_VALUE_) { - // skip lead surrogate code units, - // go to lead surrogate codepoints - m_nextIndex_ = BMP_INDEX_LENGTH_; - } - else if (m_nextCodepoint_ == TRAIL_SURROGATE_MIN_VALUE_) { - // go back to regular BMP code points - m_nextIndex_ = m_nextCodepoint_ >> Trie.INDEX_STAGE_1_SHIFT_; - } - - m_nextBlockIndex_ = 0; - if (!checkBlock(currentBlock, currentValue)) { - setResult(element, m_currentCodepoint_, m_nextCodepoint_, - currentValue); - return true; - } - } - m_nextCodepoint_ --; // step one back since this value has not been - m_nextBlockIndex_ --; // retrieved yet. - return false; - } - - /** - * Finds the next supplementary element. - * For each entry in the trie, the value to be delivered is passed through - * extract(). - * We always store the next element before it is requested. - * Called after calculateNextBMP() completes its round of BMP characters. - * There is a slight difference in the usage of m_currentCodepoint_ - * here as compared to calculateNextBMP(). Though both represents the - * lower bound of the next element, in calculateNextBMP() it gets set - * at the start of any loop, where-else, in calculateNextSupplementary() - * since m_currentCodepoint_ already contains the lower bound of the - * next element (passed down from calculateNextBMP()), we keep it till - * the end before resetting it to the new value. - * Note, if there are no more iterations, it will never get to here. - * Blocked out by next(). - * @param element return result object - */ - private final void calculateNextSupplementaryElement(Element element) - { - int currentValue = m_nextValue_; - int currentBlock = m_nextBlock_; - m_nextCodepoint_ ++; - m_nextBlockIndex_ ++; - - if (UTF16.getTrailSurrogate(m_nextCodepoint_) - != UTF16.TRAIL_SURROGATE_MIN_VALUE) { - // this piece is only called when we are in the middle of a lead - // surrogate block - if (!checkNullNextTrailIndex() && !checkBlockDetail(currentValue)) { - setResult(element, m_currentCodepoint_, m_nextCodepoint_, - currentValue); - m_currentCodepoint_ = m_nextCodepoint_; - return; - } - // we have cleared one block - m_nextIndex_ ++; - m_nextTrailIndexOffset_ ++; - if (!checkTrailBlock(currentBlock, currentValue)) { - setResult(element, m_currentCodepoint_, m_nextCodepoint_, - currentValue); - m_currentCodepoint_ = m_nextCodepoint_; - return; - } - } - int nextLead = UTF16.getLeadSurrogate(m_nextCodepoint_); - // enumerate supplementary code points - while (nextLead < TRAIL_SURROGATE_MIN_VALUE_) { - // lead surrogate access - int leadBlock = - m_trie_.m_index_[nextLead >> Trie.INDEX_STAGE_1_SHIFT_] << - Trie.INDEX_STAGE_2_SHIFT_; - if (leadBlock == m_trie_.m_dataOffset_) { - // no entries for a whole block of lead surrogates - if (currentValue != m_initialValue_) { - m_nextValue_ = m_initialValue_; - m_nextBlock_ = 0; - m_nextBlockIndex_ = 0; - setResult(element, m_currentCodepoint_, m_nextCodepoint_, - currentValue); - m_currentCodepoint_ = m_nextCodepoint_; - return; - } - - nextLead += DATA_BLOCK_LENGTH_; - // number of total affected supplementary codepoints in one - // block - // this is not a simple addition of - // DATA_BLOCK_SUPPLEMENTARY_LENGTH since we need to consider - // that we might have moved some of the codepoints - m_nextCodepoint_ = UCharacterProperty.getRawSupplementary( - (char)nextLead, - (char)UTF16.TRAIL_SURROGATE_MIN_VALUE); - continue; - } - if (m_trie_.m_dataManipulate_ == null) { - throw new NullPointerException( - "The field DataManipulate in this Trie is null"); - } - // enumerate trail surrogates for this lead surrogate - m_nextIndex_ = m_trie_.m_dataManipulate_.getFoldingOffset( - m_trie_.getValue(leadBlock + - (nextLead & Trie.INDEX_STAGE_3_MASK_))); - if (m_nextIndex_ <= 0) { - // no data for this lead surrogate - if (currentValue != m_initialValue_) { - m_nextValue_ = m_initialValue_; - m_nextBlock_ = 0; - m_nextBlockIndex_ = 0; - setResult(element, m_currentCodepoint_, m_nextCodepoint_, - currentValue); - m_currentCodepoint_ = m_nextCodepoint_; - return; - } - m_nextCodepoint_ += TRAIL_SURROGATE_COUNT_; - } else { - m_nextTrailIndexOffset_ = 0; - if (!checkTrailBlock(currentBlock, currentValue)) { - setResult(element, m_currentCodepoint_, m_nextCodepoint_, - currentValue); - m_currentCodepoint_ = m_nextCodepoint_; - return; - } - } - nextLead ++; - } - - // deliver last range - setResult(element, m_currentCodepoint_, UCharacter.MAX_VALUE + 1, - currentValue); - } - - /** - * Internal block value calculations - * Performs calculations on a data block to find codepoints in m_nextBlock_ - * after the index m_nextBlockIndex_ that has the same value. - * Note m_*_ variables at this point is the next codepoint whose value - * has not been calculated. - * But when returned with false, it will be the last codepoint whose - * value has been calculated. - * @param currentValue the value which other codepoints are tested against - * @return true if the whole block has the same value as currentValue or if - * the whole block has been calculated, false otherwise. - */ - private final boolean checkBlockDetail(int currentValue) - { - while (m_nextBlockIndex_ < DATA_BLOCK_LENGTH_) { - m_nextValue_ = extract(m_trie_.getValue(m_nextBlock_ + - m_nextBlockIndex_)); - if (m_nextValue_ != currentValue) { - return false; - } - ++ m_nextBlockIndex_; - ++ m_nextCodepoint_; - } - return true; - } - - /** - * Internal block value calculations - * Performs calculations on a data block to find codepoints in m_nextBlock_ - * that has the same value. - * Will call checkBlockDetail() if highlevel check fails. - * Note m_*_ variables at this point is the next codepoint whose value - * has not been calculated. - * @param currentBlock the initial block containing all currentValue - * @param currentValue the value which other codepoints are tested against - * @return true if the whole block has the same value as currentValue or if - * the whole block has been calculated, false otherwise. - */ - private final boolean checkBlock(int currentBlock, int currentValue) - { - m_nextBlock_ = m_trie_.m_index_[m_nextIndex_] << - Trie.INDEX_STAGE_2_SHIFT_; - if (m_nextBlock_ == currentBlock && - (m_nextCodepoint_ - m_currentCodepoint_) >= DATA_BLOCK_LENGTH_) { - // the block is the same as the previous one, filled with - // currentValue - m_nextCodepoint_ += DATA_BLOCK_LENGTH_; - } - else if (m_nextBlock_ == 0) { - // this is the all-initial-value block - if (currentValue != m_initialValue_) { - m_nextValue_ = m_initialValue_; - m_nextBlockIndex_ = 0; - return false; - } - m_nextCodepoint_ += DATA_BLOCK_LENGTH_; - } - else { - if (!checkBlockDetail(currentValue)) { - return false; - } - } - return true; - } - - /** - * Internal block value calculations - * Performs calculations on multiple data blocks for a set of trail - * surrogates to find codepoints in m_nextBlock_ that has the same value. - * Will call checkBlock() for internal block checks. - * Note m_*_ variables at this point is the next codepoint whose value - * has not been calculated. - * @param currentBlock the initial block containing all currentValue - * @param currentValue the value which other codepoints are tested against - * @return true if the whole block has the same value as currentValue or if - * the whole block has been calculated, false otherwise. - */ - private final boolean checkTrailBlock(int currentBlock, - int currentValue) - { - // enumerate code points for this lead surrogate - while (m_nextTrailIndexOffset_ < TRAIL_SURROGATE_INDEX_BLOCK_LENGTH_) - { - // if we ever reach here, we are at the start of a new block - m_nextBlockIndex_ = 0; - // copy of most of the body of the BMP loop - if (!checkBlock(currentBlock, currentValue)) { - return false; - } - m_nextTrailIndexOffset_ ++; - m_nextIndex_ ++; - } - return true; - } - - /** - * Checks if we are beginning at the start of a initial block. - * If we are then the rest of the codepoints in this initial block - * has the same values. - * We increment m_nextCodepoint_ and relevant data members if so. - * This is used only in for the supplementary codepoints because - * the offset to the trail indexes could be 0. - * @return true if we are at the start of a initial block. - */ - private final boolean checkNullNextTrailIndex() - { - if (m_nextIndex_ <= 0) { - m_nextCodepoint_ += TRAIL_SURROGATE_COUNT_ - 1; - int nextLead = UTF16.getLeadSurrogate(m_nextCodepoint_); - int leadBlock = - m_trie_.m_index_[nextLead >> Trie.INDEX_STAGE_1_SHIFT_] << - Trie.INDEX_STAGE_2_SHIFT_; - if (m_trie_.m_dataManipulate_ == null) { - throw new NullPointerException( - "The field DataManipulate in this Trie is null"); - } - m_nextIndex_ = m_trie_.m_dataManipulate_.getFoldingOffset( - m_trie_.getValue(leadBlock + - (nextLead & Trie.INDEX_STAGE_3_MASK_))); - m_nextIndex_ --; - m_nextBlockIndex_ = DATA_BLOCK_LENGTH_; - return true; - } - return false; - } - - // private data members -------------------------------------------- - - /** - * Size of the stage 1 BMP indexes - */ - private static final int BMP_INDEX_LENGTH_ = - 0x10000 >> Trie.INDEX_STAGE_1_SHIFT_; - /** - * Lead surrogate minimum value - */ - private static final int LEAD_SURROGATE_MIN_VALUE_ = 0xD800; - /** - * Trail surrogate minimum value - */ - private static final int TRAIL_SURROGATE_MIN_VALUE_ = 0xDC00; - /** - * Number of trail surrogate - */ - private static final int TRAIL_SURROGATE_COUNT_ = 0x400; - /** - * Number of stage 1 indexes for supplementary calculations that maps to - * each lead surrogate character. - * See second pass into getRawOffset for the trail surrogate character. - * 10 for significant number of bits for trail surrogates, 5 for what we - * discard during shifting. - */ - private static final int TRAIL_SURROGATE_INDEX_BLOCK_LENGTH_ = - 1 << (10 - Trie.INDEX_STAGE_1_SHIFT_); - /** - * Number of data values in a stage 2 (data array) block. - */ - private static final int DATA_BLOCK_LENGTH_ = - 1 << Trie.INDEX_STAGE_1_SHIFT_; - /** - * Trie instance - */ - private Trie m_trie_; - /** - * Initial value for trie values - */ - private int m_initialValue_; - /** - * Next element results and data. - */ - private int m_currentCodepoint_; - private int m_nextCodepoint_; - private int m_nextValue_; - private int m_nextIndex_; - private int m_nextBlock_; - private int m_nextBlockIndex_; - private int m_nextTrailIndexOffset_; -} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/UBiDiProps.java b/jdk/src/java.base/share/classes/sun/text/normalizer/UBiDiProps.java index c7ac9aeac61..453cc0c5f38 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/UBiDiProps.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/UBiDiProps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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,74 +24,71 @@ */ /* ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * + * + * Copyright (C) 2004-2014, International Business Machines + * Corporation and others. All Rights Reserved. + * ******************************************************************************* -* file name: UBiDiProps.java -* encoding: US-ASCII -* tab size: 8 (not used) -* indentation:4 -* -* created on: 2005jan16 -* created by: Markus W. Scherer -* -* Low-level Unicode bidi/shaping properties access. -* Java port of ubidi_props.h/.c. -*/ + * file name: UBiDiProps.java + * encoding: US-ASCII + * tab size: 8 (not used) + * indentation:4 + * + * created on: 2005jan16 + * created by: Markus W. Scherer + * + * Low-level Unicode bidi/shaping properties access. + * Java port of ubidi_props.h/.c. + */ package sun.text.normalizer; -import java.io.BufferedInputStream; -import java.io.DataInputStream; -import java.io.InputStream; import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.MissingResourceException; public final class UBiDiProps { // constructors etc. --------------------------------------------------- *** // port of ubidi_openProps() - public UBiDiProps() throws IOException{ - InputStream is=ICUData.getStream(DATA_FILE_NAME); - BufferedInputStream b=new BufferedInputStream(is, 4096 /* data buffer size */); - readData(b); - b.close(); - is.close(); - + private UBiDiProps() throws IOException{ + ByteBuffer bytes=ICUBinary.getRequiredData(DATA_FILE_NAME); + readData(bytes); } - private void readData(InputStream is) throws IOException { - DataInputStream inputStream=new DataInputStream(is); - + private void readData(ByteBuffer bytes) throws IOException { // read the header - ICUBinary.readHeader(inputStream, FMT, new IsAcceptable()); + ICUBinary.readHeader(bytes, FMT, new IsAcceptable()); // read indexes[] int i, count; - count=inputStream.readInt(); - if(count<IX_INDEX_TOP) { + count=bytes.getInt(); + if(count<IX_TOP) { throw new IOException("indexes[0] too small in "+DATA_FILE_NAME); } indexes=new int[count]; indexes[0]=count; for(i=1; i<count; ++i) { - indexes[i]=inputStream.readInt(); + indexes[i]=bytes.getInt(); } // read the trie - trie=new CharTrie(inputStream, null); + trie=Trie2_16.createFromSerialized(bytes); + int expectedTrieLength=indexes[IX_TRIE_SIZE]; + int trieLength=trie.getSerializedLength(); + if(trieLength>expectedTrieLength) { + throw new IOException(DATA_FILE_NAME+": not enough bytes for the trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength-trieLength); // read mirrors[] count=indexes[IX_MIRROR_LENGTH]; if(count>0) { mirrors=new int[count]; for(i=0; i<count; ++i) { - mirrors[i]=inputStream.readInt(); + mirrors[i]=bytes.getInt(); } } @@ -99,81 +96,172 @@ public final class UBiDiProps { count=indexes[IX_JG_LIMIT]-indexes[IX_JG_START]; jgArray=new byte[count]; for(i=0; i<count; ++i) { - jgArray[i]=inputStream.readByte(); + jgArray[i]=bytes.get(); + } + + // read jgArray2[] + count=indexes[IX_JG_LIMIT2]-indexes[IX_JG_START2]; + jgArray2=new byte[count]; + for(i=0; i<count; ++i) { + jgArray2[i]=bytes.get(); } } // implement ICUBinary.Authenticate - private final class IsAcceptable implements ICUBinary.Authenticate { + private final static class IsAcceptable implements ICUBinary.Authenticate { public boolean isDataVersionAcceptable(byte version[]) { - return version[0]==1 && - version[2]==Trie.INDEX_STAGE_1_SHIFT_ && version[3]==Trie.INDEX_STAGE_2_SHIFT_; + return version[0]==2; } } - // UBiDiProps singleton - private static UBiDiProps gBdp=null; - - // port of ubidi_getSingleton() - public static final synchronized UBiDiProps getSingleton() throws IOException { - if(gBdp==null) { - gBdp=new UBiDiProps(); - } - return gBdp; - } - - // UBiDiProps dummy singleton - private static UBiDiProps gBdpDummy=null; - - private UBiDiProps(boolean makeDummy) { // ignore makeDummy, only creates a unique signature - indexes=new int[IX_TOP]; - indexes[0]=IX_TOP; - trie=new CharTrie(0, 0, null); // dummy trie, always returns 0 - } - - /** - * Get a singleton dummy object, one that works with no real data. - * This can be used when the real data is not available. - * Using the dummy can reduce checks for available data after an initial failure. - * Port of ucase_getDummy(). - */ - public static final synchronized UBiDiProps getDummy() { - if(gBdpDummy==null) { - gBdpDummy=new UBiDiProps(true); - } - return gBdpDummy; - } + // property access functions ------------------------------------------- *** public final int getClass(int c) { - return getClassFromProps(trie.getCodePointValue(c)); + return getClassFromProps(trie.get(c)); + } + + private final int getMirror(int c, int props) { + int delta=getMirrorDeltaFromProps(props); + if(delta!=ESC_MIRROR_DELTA) { + return c+delta; + } else { + /* look for mirror code point in the mirrors[] table */ + int m; + int i, length; + int c2; + + length=indexes[IX_MIRROR_LENGTH]; + + /* linear search */ + for(i=0; i<length; ++i) { + m=mirrors[i]; + c2=getMirrorCodePoint(m); + if(c==c2) { + /* found c, return its mirror code point using the index in m */ + return getMirrorCodePoint(mirrors[getMirrorIndex(m)]); + } else if(c<c2) { + break; + } + } + + /* c not found, return it itself */ + return c; + } + } + + public final int getMirror(int c) { + int props=trie.get(c); + return getMirror(c, props); + } + + public final int getJoiningType(int c) { + return (trie.get(c)&JT_MASK)>>JT_SHIFT; + } + + public final int getJoiningGroup(int c) { + int start, limit; + + start=indexes[IX_JG_START]; + limit=indexes[IX_JG_LIMIT]; + if(start<=c && c<limit) { + return (int)jgArray[c-start]&0xff; + } + start=indexes[IX_JG_START2]; + limit=indexes[IX_JG_LIMIT2]; + if(start<=c && c<limit) { + return (int)jgArray2[c-start]&0xff; + } + return UCharacter.JoiningGroup.NO_JOINING_GROUP; + } + + public final int getPairedBracketType(int c) { + return (trie.get(c)&BPT_MASK)>>BPT_SHIFT; + } + + public final int getPairedBracket(int c) { + int props=trie.get(c); + if((props&BPT_MASK)==0) { + return c; + } else { + return getMirror(c, props); + } } // data members -------------------------------------------------------- *** private int indexes[]; private int mirrors[]; private byte jgArray[]; + private byte jgArray2[]; - private CharTrie trie; + private Trie2_16 trie; // data format constants ----------------------------------------------- *** private static final String DATA_FILE_NAME = "/sun/text/resources/ubidi.icu"; /* format "BiDi" */ - private static final byte FMT[]={ 0x42, 0x69, 0x44, 0x69 }; + private static final int FMT=0x42694469; /* indexes into indexes[] */ - private static final int IX_INDEX_TOP=0; + private static final int IX_TRIE_SIZE=2; private static final int IX_MIRROR_LENGTH=3; private static final int IX_JG_START=4; private static final int IX_JG_LIMIT=5; + private static final int IX_JG_START2=6; /* new in format version 2.2, ICU 54 */ + private static final int IX_JG_LIMIT2=7; private static final int IX_TOP=16; + // definitions for 16-bit bidi/shaping properties word ----------------- *** + + /* CLASS_SHIFT=0, */ /* bidi class: 5 bits (4..0) */ + private static final int JT_SHIFT=5; /* joining type: 3 bits (7..5) */ + + private static final int BPT_SHIFT=8; /* Bidi_Paired_Bracket_Type(bpt): 2 bits (9..8) */ + + private static final int MIRROR_DELTA_SHIFT=13; /* bidi mirroring delta: 3 bits (15..13) */ + private static final int CLASS_MASK= 0x0000001f; + private static final int JT_MASK= 0x000000e0; + private static final int BPT_MASK= 0x00000300; private static final int getClassFromProps(int props) { return props&CLASS_MASK; } + private static final boolean getFlagFromProps(int props, int shift) { + return ((props>>shift)&1)!=0; + } + private static final int getMirrorDeltaFromProps(int props) { + return (short)props>>MIRROR_DELTA_SHIFT; + } + private static final int ESC_MIRROR_DELTA=-4; + + // definitions for 32-bit mirror table entry --------------------------- *** + + /* the source Unicode code point takes 21 bits (20..0) */ + private static final int MIRROR_INDEX_SHIFT=21; + + private static final int getMirrorCodePoint(int m) { + return m&0x1fffff; + } + private static final int getMirrorIndex(int m) { + return m>>>MIRROR_INDEX_SHIFT; + } + + + /* + * public singleton instance + */ + public static final UBiDiProps INSTANCE; + + // This static initializer block must be placed after + // other static member initialization + static { + try { + INSTANCE = new UBiDiProps(); + } catch (IOException e) { + throw new MissingResourceException(e.getMessage(),DATA_FILE_NAME,""); + } + } } diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacter.java b/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacter.java index 5382d16012d..579a8996104 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacter.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * 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,40 +22,30 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -/* - ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ + +/** +******************************************************************************* +* Copyright (C) 1996-2014, International Business Machines Corporation and +* others. All Rights Reserved. +******************************************************************************* +*/ package sun.text.normalizer; -import java.io.IOException; -import java.util.MissingResourceException; - /** - * <p> - * The UCharacter class provides extensions to the - * <a href="http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Character.html"> + * <p>The UCharacter class provides extensions to the + * <a href="http://java.sun.com/j2se/1.5/docs/api/java/lang/Character.html"> * java.lang.Character</a> class. These extensions provide support for * more Unicode properties and together with the <a href=../text/UTF16.html>UTF16</a> * class, provide support for supplementary characters (those with code * points above U+FFFF). * Each ICU release supports the latest version of Unicode available at that time. - * </p> - * <p> - * Code points are represented in these API using ints. While it would be + * + * <p>Code points are represented in these API using ints. While it would be * more convenient in Java to have a separate primitive datatype for them, * ints suffice in the meantime. - * </p> - * <p> - * To use this class please add the jar file name icu4j.jar to the + * + * <p>To use this class please add the jar file name icu4j.jar to the * class path, since it contains data files which supply the information used * by this file.<br> * E.g. In Windows <br> @@ -64,9 +54,8 @@ import java.util.MissingResourceException; * unames.icu from the icu4j source subdirectory * <i>$ICU4J_SRC/src/com.ibm.icu.impl.data</i> to your class directory * <i>$ICU4J_CLASS/com.ibm.icu.impl.data</i>. - * </p> - * <p> - * Aside from the additions for UTF-16 support, and the updated Unicode + * + * <p>Aside from the additions for UTF-16 support, and the updated Unicode * properties, the main differences between UCharacter and Character are: * <ul> * <li> UCharacter is not designed to be a char wrapper and does not have @@ -87,8 +76,9 @@ import java.util.MissingResourceException; * as having numeric values. This is a semantic change from ICU4J 1.3.1. * </ul> * <p> - * Further detail differences can be determined from the program - * <a href="http://source.icu-project.org/repos/icu/icu4j/trunk/src/com/ibm/icu/dev/test/lang/UCharacterCompare.java"> + * Further detail on differences can be determined using the program + * <a href= + * "http://source.icu-project.org/repos/icu/icu4j/trunk/src/com/ibm/icu/dev/test/lang/UCharacterCompare.java"> * com.ibm.icu.dev.test.lang.UCharacterCompare</a> * </p> * <p> @@ -103,8 +93,11 @@ import java.util.MissingResourceException; * </p> * <p> * For more information see - * "About the Unicode Character Database" (http://www.unicode.org/ucd/) - * and the ICU User Guide chapter on Properties (http://www.icu-project.org/userguide/properties.html). + * <a href="http://www.unicode/org/ucd/">"About the Unicode Character Database"</a> + * (http://www.unicode.org/ucd/) + * and the <a href="http://www.icu-project.org/userguide/properties.html">ICU + * User Guide chapter on Properties</a> + * (http://www.icu-project.org/userguide/properties.html). * </p> * <p> * There are also functions that provide easy migration from C/POSIX functions @@ -128,12 +121,15 @@ import java.util.MissingResourceException; * Annex C: Compatibility Properties of UTS #18 Unicode Regular Expressions * (http://www.unicode.org/reports/tr18/#Compatibility_Properties). * </p> - * <pre>{@code + * <p> * API access for C/POSIX character classes is as follows: + * <pre>{@code * - alpha: isUAlphabetic(c) or hasBinaryProperty(c, UProperty.ALPHABETIC) * - lower: isULowercase(c) or hasBinaryProperty(c, UProperty.LOWERCASE) * - upper: isUUppercase(c) or hasBinaryProperty(c, UProperty.UPPERCASE) - * - punct: ((1<<getType(c)) & ((1<<DASH_PUNCTUATION)|(1<<START_PUNCTUATION)|(1<<END_PUNCTUATION)|(1<<CONNECTOR_PUNCTUATION)|(1<<OTHER_PUNCTUATION)|(1<<INITIAL_PUNCTUATION)|(1<<FINAL_PUNCTUATION)))!=0 + * - punct: ((1<<getType(c)) & ((1<<DASH_PUNCTUATION)|(1<<START_PUNCTUATION)| + * (1<<END_PUNCTUATION)|(1<<CONNECTOR_PUNCTUATION)|(1<<OTHER_PUNCTUATION)| + * (1<<INITIAL_PUNCTUATION)|(1<<FINAL_PUNCTUATION)))!=0 * - digit: isDigit(c) or getType(c)==DECIMAL_DIGIT_NUMBER * - xdigit: hasBinaryProperty(c, UProperty.POSIX_XDIGIT) * - alnum: hasBinaryProperty(c, UProperty.POSIX_ALNUM) @@ -143,21 +139,22 @@ import java.util.MissingResourceException; * - graph: hasBinaryProperty(c, UProperty.POSIX_GRAPH) * - print: hasBinaryProperty(c, UProperty.POSIX_PRINT) * }</pre> + * </p> * <p> * The C/POSIX character classes are also available in UnicodeSet patterns, * using patterns like [:graph:] or \p{graph}. * </p> - * <p> - * Note: There are several ICU (and Java) whitespace functions. - * Comparison: - * - isUWhiteSpace=UCHAR_WHITE_SPACE: Unicode White_Space property; + * + * There are several ICU (and Java) whitespace functions. + * Comparison:<ul> + * <li> isUWhiteSpace=UCHAR_WHITE_SPACE: Unicode White_Space property; * most of general categories "Z" (separators) + most whitespace ISO controls * (including no-break spaces, but excluding IS1..IS4 and ZWSP) - * - isWhitespace: Java isWhitespace; Z + whitespace ISO controls but excluding no-break spaces - * - isSpaceChar: just Z (including no-break spaces) + * <li> isWhitespace: Java isWhitespace; Z + whitespace ISO controls but excluding no-break spaces + * <li> isSpaceChar: just Z (including no-break spaces)</ul> * </p> * <p> - * This class is not subclassable + * This class is not subclassable. * </p> * @author Syn Wee Quek * @stable ICU 2.1 @@ -167,6 +164,19 @@ import java.util.MissingResourceException; public final class UCharacter { + /** + * Joining Group constants. + * @see UProperty#JOINING_GROUP + * @stable ICU 2.4 + */ + public static interface JoiningGroup + { + /** + * @stable ICU 2.4 + */ + public static final int NO_JOINING_GROUP = 0; + } + /** * Numeric Type constants. * @see UProperty#NUMERIC_TYPE @@ -174,10 +184,64 @@ public final class UCharacter */ public static interface NumericType { + /** + * @stable ICU 2.4 + */ + public static final int NONE = 0; /** * @stable ICU 2.4 */ public static final int DECIMAL = 1; + /** + * @stable ICU 2.4 + */ + public static final int DIGIT = 2; + /** + * @stable ICU 2.4 + */ + public static final int NUMERIC = 3; + /** + * @stable ICU 2.4 + */ + public static final int COUNT = 4; + } + + /** + * Hangul Syllable Type constants. + * + * @see UProperty#HANGUL_SYLLABLE_TYPE + * @stable ICU 2.6 + */ + public static interface HangulSyllableType + { + /** + * @stable ICU 2.6 + */ + public static final int NOT_APPLICABLE = 0; /*[NA]*/ /*See note !!*/ + /** + * @stable ICU 2.6 + */ + public static final int LEADING_JAMO = 1; /*[L]*/ + /** + * @stable ICU 2.6 + */ + public static final int VOWEL_JAMO = 2; /*[V]*/ + /** + * @stable ICU 2.6 + */ + public static final int TRAILING_JAMO = 3; /*[T]*/ + /** + * @stable ICU 2.6 + */ + public static final int LV_SYLLABLE = 4; /*[LV]*/ + /** + * @stable ICU 2.6 + */ + public static final int LVT_SYLLABLE = 5; /*[LVT]*/ + /** + * @stable ICU 2.6 + */ + public static final int COUNT = 6; } // public data members ----------------------------------------------- @@ -192,22 +256,15 @@ public final class UCharacter * The highest Unicode code point value (scalar value) according to the * Unicode Standard. * This is a 21-bit value (21 bits, rounded up).<br> - * Up-to-date Unicode implementation of java.lang.Character.MIN_VALUE + * Up-to-date Unicode implementation of java.lang.Character.MAX_VALUE * @stable ICU 2.1 */ public static final int MAX_VALUE = UTF16.CODEPOINT_MAX_VALUE; - /** - * The minimum value for Supplementary code points - * @stable ICU 2.1 - */ - public static final int SUPPLEMENTARY_MIN_VALUE = - UTF16.SUPPLEMENTARY_MIN_VALUE; - // public methods ---------------------------------------------------- /** - * Retrieves the numeric value of a decimal digit code point. + * Returns the numeric value of a decimal digit code point. * <br>This method observes the semantics of * <code>java.lang.Character.digit()</code>. Note that this * will return positive values for code points for which isDigit @@ -231,15 +288,54 @@ public final class UCharacter */ public static int digit(int ch, int radix) { - // when ch is out of bounds getProperty == 0 - int props = getProperty(ch); - int value; - if (getNumericType(props) == NumericType.DECIMAL) { - value = UCharacterProperty.getUnsignedValue(props); + if (2 <= radix && radix <= 36) { + int value = digit(ch); + if (value < 0) { + // ch is not a decimal digit, try latin letters + value = UCharacterProperty.getEuropeanDigit(ch); + } + return (value < radix) ? value : -1; } else { - value = getEuropeanDigit(ch); + return -1; // invalid radix } - return (0 <= value && value < radix) ? value : -1; + } + + /** + * Returns the numeric value of a decimal digit code point. + * <br>This is a convenience overload of <code>digit(int, int)</code> + * that provides a decimal radix. + * <br><em>Semantic Change:</em> In release 1.3.1 and prior, this + * treated numeric letters and other numbers as digits. This has + * been changed to conform to the java semantics. + * @param ch the code point to query + * @return the numeric value represented by the code point, + * or -1 if the code point is not a decimal digit or if its + * value is too large for a decimal radix + * @stable ICU 2.1 + */ + public static int digit(int ch) + { + return UCharacterProperty.INSTANCE.digit(ch); + } + + /** + * Returns a value indicating a code point's Unicode category. + * Up-to-date Unicode implementation of java.lang.Character.getType() + * except for the above mentioned code points that had their category + * changed.<br> + * Return results are constants from the interface + * <a href=UCharacterCategory.html>UCharacterCategory</a><br> + * <em>NOTE:</em> the UCharacterCategory values are <em>not</em> compatible with + * those returned by java.lang.Character.getType. UCharacterCategory values + * match the ones used in ICU4C, while java.lang.Character type + * values, though similar, skip the value 17.</p> + * @param ch code point whose type is to be determined + * @return category which is a value of UCharacterCategory + * @stable ICU 2.1 + */ + public static int getType(int ch) + { + return UCharacterProperty.INSTANCE.getType(ch); } /** @@ -254,7 +350,67 @@ public final class UCharacter */ public static int getDirection(int ch) { - return gBdp.getClass(ch); + return UBiDiProps.INSTANCE.getClass(ch); + } + + /** + * Maps the specified code point to a "mirror-image" code point. + * For code points with the "mirrored" property, implementations sometimes + * need a "poor man's" mapping to another code point such that the default + * glyph may serve as the mirror-image of the default glyph of the + * specified code point.<br> + * This is useful for text conversion to and from codepages with visual + * order, and for displays without glyph selection capabilities. + * @param ch code point whose mirror is to be retrieved + * @return another code point that may serve as a mirror-image substitute, + * or ch itself if there is no such mapping or ch does not have the + * "mirrored" property + * @stable ICU 2.1 + */ + public static int getMirror(int ch) + { + return UBiDiProps.INSTANCE.getMirror(ch); + } + + /** + * Maps the specified character to its paired bracket character. + * For Bidi_Paired_Bracket_Type!=None, this is the same as getMirror(int). + * Otherwise c itself is returned. + * See http://www.unicode.org/reports/tr9/ + * + * @param c the code point to be mapped + * @return the paired bracket code point, + * or c itself if there is no such mapping + * (Bidi_Paired_Bracket_Type=None) + * + * @see UProperty#BIDI_PAIRED_BRACKET + * @see UProperty#BIDI_PAIRED_BRACKET_TYPE + * @see #getMirror(int) + * @stable ICU 52 + */ + public static int getBidiPairedBracket(int c) { + return UBiDiProps.INSTANCE.getPairedBracket(c); + } + + /** + * Returns the combining class of the argument codepoint + * @param ch code point whose combining is to be retrieved + * @return the combining class of the codepoint + * @stable ICU 2.1 + */ + public static int getCombiningClass(int ch) + { + return Normalizer2.getNFDInstance().getCombiningClass(ch); + } + + /** + * Returns the version of Unicode data used. + * @return the unicode version number used + * @stable ICU 2.1 + */ + public static VersionInfo getUnicodeVersion() + { + return UCharacterProperty.INSTANCE.m_unicodeVersion_; } /** @@ -275,7 +431,7 @@ public final class UCharacter } /** - * <p>Get the "age" of the code point.</p> + * Returns the "age" of the code point.</p> * <p>The "age" is the Unicode version when the code point was first * designated (as a non-character or for Private Use) or assigned a * character. @@ -289,143 +445,95 @@ public final class UCharacter public static VersionInfo getAge(int ch) { if (ch < MIN_VALUE || ch > MAX_VALUE) { - throw new IllegalArgumentException("Codepoint out of bounds"); + throw new IllegalArgumentException("Codepoint out of bounds"); } - return PROPERTY_.getAge(ch); - } - - // private variables ------------------------------------------------- - - /** - * Database storing the sets of character property - */ - private static final UCharacterProperty PROPERTY_; - /** - * For optimization - */ - private static final char[] PROPERTY_TRIE_INDEX_; - private static final char[] PROPERTY_TRIE_DATA_; - private static final int PROPERTY_INITIAL_VALUE_; - - private static final UBiDiProps gBdp; - - // block to initialise character property database - static - { - try - { - PROPERTY_ = UCharacterProperty.getInstance(); - PROPERTY_TRIE_INDEX_ = PROPERTY_.m_trieIndex_; - PROPERTY_TRIE_DATA_ = PROPERTY_.m_trieData_; - PROPERTY_INITIAL_VALUE_ = PROPERTY_.m_trieInitialValue_; - } - catch (Exception e) - { - throw new MissingResourceException(e.getMessage(),"",""); - } - - UBiDiProps bdp; - try { - bdp=UBiDiProps.getSingleton(); - } catch(IOException e) { - bdp=UBiDiProps.getDummy(); - } - gBdp=bdp; + return UCharacterProperty.INSTANCE.getAge(ch); } /** - * Shift to get numeric type + * Returns the property value for an Unicode property type of a code point. + * Also returns binary and mask property values.</p> + * <p>Unicode, especially in version 3.2, defines many more properties than + * the original set in UnicodeData.txt.</p> + * <p>The properties APIs are intended to reflect Unicode properties as + * defined in the Unicode Character Database (UCD) and Unicode Technical + * Reports (UTR). For details about the properties see + * http://www.unicode.org/.</p> + * <p>For names of Unicode properties see the UCD file PropertyAliases.txt. + * </p> + * <pre> + * Sample usage: + * int ea = UCharacter.getIntPropertyValue(c, UProperty.EAST_ASIAN_WIDTH); + * int ideo = UCharacter.getIntPropertyValue(c, UProperty.IDEOGRAPHIC); + * boolean b = (ideo == 1) ? true : false; + * </pre> + * @param ch code point to test. + * @param type UProperty selector constant, identifies which binary + * property to check. Must be + * UProperty.BINARY_START <= type < UProperty.BINARY_LIMIT or + * UProperty.INT_START <= type < UProperty.INT_LIMIT or + * UProperty.MASK_START <= type < UProperty.MASK_LIMIT. + * @return numeric value that is directly the property value or, + * for enumerated properties, corresponds to the numeric value of + * the enumerated constant of the respective property value + * enumeration type (cast to enum type if necessary). + * Returns 0 or 1 (for false / true) for binary Unicode properties. + * Returns a bit-mask for mask properties. + * Returns 0 if 'type' is out of bounds or if the Unicode version + * does not have data for the property at all, or not for this code + * point. + * @see UProperty + * @see #hasBinaryProperty + * @see #getIntPropertyMinValue + * @see #getIntPropertyMaxValue + * @see #getUnicodeVersion + * @stable ICU 2.4 */ - private static final int NUMERIC_TYPE_SHIFT_ = 5; - /** - * Mask to get numeric type - */ - private static final int NUMERIC_TYPE_MASK_ = 0x7 << NUMERIC_TYPE_SHIFT_; - - // private methods --------------------------------------------------- - - /** - * Getting the digit values of characters like 'A' - 'Z', normal, - * half-width and full-width. This method assumes that the other digit - * characters are checked by the calling method. - * @param ch character to test - * @return -1 if ch is not a character of the form 'A' - 'Z', otherwise - * its corresponding digit will be returned. - */ - private static int getEuropeanDigit(int ch) { - if ((ch > 0x7a && ch < 0xff21) - || ch < 0x41 || (ch > 0x5a && ch < 0x61) - || ch > 0xff5a || (ch > 0xff3a && ch < 0xff41)) { - return -1; - } - if (ch <= 0x7a) { - // ch >= 0x41 or ch < 0x61 - return ch + 10 - ((ch <= 0x5a) ? 0x41 : 0x61); - } - // ch >= 0xff21 - if (ch <= 0xff3a) { - return ch + 10 - 0xff21; - } - // ch >= 0xff41 && ch <= 0xff5a - return ch + 10 - 0xff41; + // for BiDiBase.java + public static int getIntPropertyValue(int ch, int type) { + return UCharacterProperty.INSTANCE.getIntPropertyValue(ch, type); } - /** - * Gets the numeric type of the property argument - * @param props 32 bit property - * @return the numeric type - */ - private static int getNumericType(int props) - { - return (props & NUMERIC_TYPE_MASK_) >> NUMERIC_TYPE_SHIFT_; - } + // private constructor ----------------------------------------------- /** - * Gets the property value at the index. - * This is optimized. - * Note this is alittle different from CharTrie the index m_trieData_ - * is never negative. - * This is a duplicate of UCharacterProperty.getProperty. For optimization - * purposes, this method calls the trie data directly instead of through - * UCharacterProperty.getProperty. - * @param ch code point whose property value is to be retrieved - * @return property value of code point - * @stable ICU 2.6 + * Private constructor to prevent instantiation */ - private static final int getProperty(int ch) - { - if (ch < UTF16.LEAD_SURROGATE_MIN_VALUE - || (ch > UTF16.LEAD_SURROGATE_MAX_VALUE - && ch < UTF16.SUPPLEMENTARY_MIN_VALUE)) { - // BMP codepoint 0000..D7FF or DC00..FFFF - try { // using try for ch < 0 is faster than using an if statement - return PROPERTY_TRIE_DATA_[ - (PROPERTY_TRIE_INDEX_[ch >> 5] << 2) - + (ch & 0x1f)]; - } catch (ArrayIndexOutOfBoundsException e) { - return PROPERTY_INITIAL_VALUE_; - } - } - if (ch <= UTF16.LEAD_SURROGATE_MAX_VALUE) { - // lead surrogate D800..DBFF - return PROPERTY_TRIE_DATA_[ - (PROPERTY_TRIE_INDEX_[(0x2800 >> 5) + (ch >> 5)] << 2) - + (ch & 0x1f)]; - } - // for optimization - if (ch <= UTF16.CODEPOINT_MAX_VALUE) { - // supplementary code point 10000..10FFFF - // look at the construction of supplementary characters - // trail forms the ends of it. - return PROPERTY_.m_trie_.getSurrogateValue( - UTF16.getLeadSurrogate(ch), - (char)(ch & 0x3ff)); - } - // return m_dataOffset_ if there is an error, in this case we return - // the default value: m_initialValue_ - // we cannot assume that m_initialValue_ is at offset 0 - // this is for optimization. - return PROPERTY_INITIAL_VALUE_; - } + private UCharacter() { } + /* + * Copied from UCharacterEnums.java + */ + + /** + * Character type Mn + * @stable ICU 2.1 + */ + public static final byte NON_SPACING_MARK = 6; + /** + * Character type Me + * @stable ICU 2.1 + */ + public static final byte ENCLOSING_MARK = 7; + /** + * Character type Mc + * @stable ICU 2.1 + */ + public static final byte COMBINING_SPACING_MARK = 8; + /** + * Character type count + * @stable ICU 2.1 + */ + public static final byte CHAR_CATEGORY_COUNT = 30; + + /** + * Directional type R + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT = 1; + /** + * Directional type AL + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_ARABIC = 13; } diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterIterator.java b/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterIterator.java index f8c41831aeb..a4983d8efda 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterIterator.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * 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,13 +25,8 @@ /* ******************************************************************************* - * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * + * Copyright (C) 1996-2014, International Business Machines Corporation and * + * others. All Rights Reserved. * ******************************************************************************* */ @@ -84,7 +79,6 @@ public abstract class UCharacterIterator return new ReplaceableUCharacterIterator(source); } - //// for StringPrep /** * Returns a <code>UCharacterIterator</code> object given a * source StringBuffer. @@ -97,7 +91,7 @@ public abstract class UCharacterIterator return new ReplaceableUCharacterIterator(source); } - /** + /** * Returns a <code>UCharacterIterator</code> object given a * CharacterIterator. * @param source a valid CharacterIterator object. @@ -111,14 +105,6 @@ public abstract class UCharacterIterator // public methods ---------------------------------------------------------- - /** - * Returns the code unit at the current index. If index is out - * of range, returns DONE. Index is not changed. - * @return current code unit - * @stable ICU 2.4 - */ - public abstract int current(); - /** * Returns the length of the text * @return length of the text @@ -126,7 +112,6 @@ public abstract class UCharacterIterator */ public abstract int getLength(); - /** * Gets the current index in text. * @return current index in text. @@ -134,7 +119,6 @@ public abstract class UCharacterIterator */ public abstract int getIndex(); - /** * Returns the UTF16 code unit at index, and increments to the next * code unit (post-increment semantics). If index is out of @@ -183,6 +167,33 @@ public abstract class UCharacterIterator */ public abstract int previous(); + + /** + * Retreat to the start of the previous code point in the text, + * and return it (pre-decrement semantics). If the index is not + * preceeded by a valid surrogate pair, the behavior is the same + * as <code>previous()</code>. Otherwise the iterator is + * decremented to the start of the surrogate pair, and the code + * point represented by the pair is returned. + * @return the previous code point in the text, or DONE if the new + * index is before the start of the text. + * @stable ICU 2.4 + */ + public int previousCodePoint(){ + int ch1 = previous(); + if(UTF16.isTrailSurrogate((char)ch1)){ + int ch2 = previous(); + if(UTF16.isLeadSurrogate((char)ch2)){ + return UCharacterProperty.getRawSupplementary((char)ch2, + (char)ch1); + }else if (ch2 != DONE) { + //unmatched trail surrogate so back out + next(); + } + } + return ch1; + } + /** * Sets the index to the specified index in the text. * @param index the index within the text. @@ -192,7 +203,14 @@ public abstract class UCharacterIterator */ public abstract void setIndex(int index); - //// for StringPrep + /** + * Sets the current index to the start. + * @stable ICU 2.4 + */ + public void setToStart() { + setIndex(0); + } + /** * Fills the buffer with the underlying text storage of the iterator * If the buffer capacity is not enough a exception is thrown. The capacity @@ -222,20 +240,19 @@ public abstract class UCharacterIterator * units. * @param offset the position within the array to start putting the data. * @return the number of code units added to fillIn, as a convenience - * @exception IndexOutOfBounds exception if there is not enough - * room after offset in the array, or if offset {@literal <} 0. + * @exception IndexOutOfBoundsException exception if there is not enough + * room after offset in the array, or if offset < 0. * @stable ICU 2.4 */ public abstract int getText(char[] fillIn, int offset); - //// for StringPrep /** * Convenience override for <code>getText(char[], int)</code> that provides * an offset of 0. * @param fillIn an array of chars to fill with the underlying UTF-16 code * units. * @return the number of code units added to fillIn, as a convenience - * @exception IndexOutOfBounds exception if there is not enough + * @exception IndexOutOfBoundsException exception if there is not enough * room in the array. * @stable ICU 2.4 */ @@ -243,7 +260,6 @@ public abstract class UCharacterIterator return getText(fillIn, 0); } - //// for StringPrep /** * Convenience method for returning the underlying text storage as a string * @return the underlying text storage in the iterator as a string @@ -256,25 +272,32 @@ public abstract class UCharacterIterator } /** - * Moves the current position by the number of code units - * specified, either forward or backward depending on the sign - * of delta (positive or negative respectively). If the resulting - * index would be less than zero, the index is set to zero, and if - * the resulting index would be greater than limit, the index is - * set to limit. - * - * @param delta the number of code units to move the current - * index. - * @return the new index. - * @exception IndexOutOfBoundsException is thrown if an invalid index is + * Moves the current position by the number of code points + * specified, either forward or backward depending on the sign of + * delta (positive or negative respectively). If the current index + * is at a trail surrogate then the first adjustment is by code + * unit, and the remaining adjustments are by code points. If the + * resulting index would be less than zero, the index is set to + * zero, and if the resulting index would be greater than limit, + * the index is set to limit. + * @param delta the number of code units to move the current index. + * @return the new index + * @exception IndexOutOfBoundsException is thrown if an invalid delta is * supplied * @stable ICU 2.4 * */ - public int moveIndex(int delta) { - int x = Math.max(0, Math.min(getIndex() + delta, getLength())); - setIndex(x); - return x; + public int moveCodePointIndex(int delta){ + if(delta>0){ + while(delta>0 && nextCodePoint() != DONE){delta--;} + }else{ + while(delta<0 && previousCodePoint() != DONE){delta++;} + } + if(delta!=0){ + throw new IndexOutOfBoundsException(); + } + + return getIndex(); } /** diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterProperty.java b/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterProperty.java index 0149140feab..83849e0e91d 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterProperty.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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,23 +24,21 @@ */ /* ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. ******************************************************************************* */ package sun.text.normalizer; -import java.io.BufferedInputStream; -import java.io.InputStream; import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Iterator; import java.util.MissingResourceException; +import sun.text.normalizer.UCharacter.HangulSyllableType; +import sun.text.normalizer.UCharacter.NumericType; + /** * <p>Internal class used for Unicode character property database.</p> * <p>This classes store binary data read from uprops.icu. @@ -56,134 +54,72 @@ import java.util.MissingResourceException; * @since release 2.1, february 1st 2002 */ -public final class UCharacterProperty +final class UCharacterProperty { // public data members ----------------------------------------------- + /* + * public singleton instance + */ + public static final UCharacterProperty INSTANCE; + /** * Trie data */ - public CharTrie m_trie_; - /** - * Optimization - * CharTrie index array - */ - public char[] m_trieIndex_; - /** - * Optimization - * CharTrie data array - */ - public char[] m_trieData_; - /** - * Optimization - * CharTrie data offset - */ - public int m_trieInitialValue_; + public Trie2_16 m_trie_; + /** * Unicode version */ public VersionInfo m_unicodeVersion_; + /** + * Character type mask + */ + public static final int TYPE_MASK = 0x1F; + // uprops.h enum UPropertySource --------------------------------------- *** + /** From uchar.c/uprops.icu main trie */ + public static final int SRC_CHAR=1; /** From uchar.c/uprops.icu properties vectors trie */ public static final int SRC_PROPSVEC=2; - /** One more than the highest UPropertySource (SRC_) constant. */ - public static final int SRC_COUNT=9; + /** From ubidi_props.c/ubidi.icu */ + public static final int SRC_BIDI=5; + /** From normalizer2impl.cpp/nfc.nrm */ + public static final int SRC_NFC=8; + /** From normalizer2impl.cpp/nfkc.nrm */ + public static final int SRC_NFKC=9; // public methods ---------------------------------------------------- /** - * Java friends implementation - */ - public void setIndexData(CharTrie.FriendAgent friendagent) - { - m_trieIndex_ = friendagent.getPrivateIndex(); - m_trieData_ = friendagent.getPrivateData(); - m_trieInitialValue_ = friendagent.getPrivateInitialValue(); - } - - /** - * Gets the property value at the index. - * This is optimized. - * Note this is alittle different from CharTrie the index m_trieData_ - * is never negative. + * Gets the main property value for code point ch. * @param ch code point whose property value is to be retrieved * @return property value of code point */ public final int getProperty(int ch) { - if (ch < UTF16.LEAD_SURROGATE_MIN_VALUE - || (ch > UTF16.LEAD_SURROGATE_MAX_VALUE - && ch < UTF16.SUPPLEMENTARY_MIN_VALUE)) { - // BMP codepoint 0000..D7FF or DC00..FFFF - // optimized - try { // using try for ch < 0 is faster than using an if statement - return m_trieData_[ - (m_trieIndex_[ch >> Trie.INDEX_STAGE_1_SHIFT_] - << Trie.INDEX_STAGE_2_SHIFT_) - + (ch & Trie.INDEX_STAGE_3_MASK_)]; - } catch (ArrayIndexOutOfBoundsException e) { - return m_trieInitialValue_; - } - } - if (ch <= UTF16.LEAD_SURROGATE_MAX_VALUE) { - // lead surrogate D800..DBFF - return m_trieData_[ - (m_trieIndex_[Trie.LEAD_INDEX_OFFSET_ - + (ch >> Trie.INDEX_STAGE_1_SHIFT_)] - << Trie.INDEX_STAGE_2_SHIFT_) - + (ch & Trie.INDEX_STAGE_3_MASK_)]; - } - if (ch <= UTF16.CODEPOINT_MAX_VALUE) { - // supplementary code point 10000..10FFFF - // look at the construction of supplementary characters - // trail forms the ends of it. - return m_trie_.getSurrogateValue( - UTF16.getLeadSurrogate(ch), - (char)(ch & Trie.SURROGATE_MASK_)); - } - // ch is out of bounds - // return m_dataOffset_ if there is an error, in this case we return - // the default value: m_initialValue_ - // we cannot assume that m_initialValue_ is at offset 0 - // this is for optimization. - return m_trieInitialValue_; - - // this all is an inlined form of return m_trie_.getCodePointValue(ch); - } - - /** - * Getting the unsigned numeric value of a character embedded in the property - * argument - * @param prop the character - * @return unsigned numberic value - */ - public static int getUnsignedValue(int prop) - { - return (prop >> VALUE_SHIFT_) & UNSIGNED_VALUE_MASK_AFTER_SHIFT_; + return m_trie_.get(ch); } /** * Gets the unicode additional properties. - * C version getUnicodeProperties. + * Java version of C u_getUnicodeProperties(). * @param codepoint codepoint whose additional properties is to be * retrieved - * @param column + * @param column The column index. * @return unicode properties */ - public int getAdditional(int codepoint, int column) { - if (column == -1) { - return getProperty(codepoint); + public int getAdditional(int codepoint, int column) { + assert column >= 0; + if (column >= m_additionalColumnsCount_) { + return 0; } - if (column < 0 || column >= m_additionalColumnsCount_) { - return 0; - } - return m_additionalVectors_[ - m_additionalTrie_.getCodePointValue(codepoint) + column]; - } + return m_additionalVectors_[m_additionalTrie_.get(codepoint) + column]; + } - /** + /** * <p>Get the "age" of the code point.</p> * <p>The "age" is the Unicode version when the code point was first * designated (as a non-character or for Private Use) or assigned a @@ -203,6 +139,91 @@ public final class UCharacterProperty version & LAST_NIBBLE_MASK_, 0, 0); } + // int-value and enumerated properties --------------------------------- *** + + public int getType(int c) { + return getProperty(c)&TYPE_MASK; + } + + /* + * Map some of the Grapheme Cluster Break values to Hangul Syllable Types. + * Hangul_Syllable_Type is fully redundant with a subset of Grapheme_Cluster_Break. + */ + private static final int /* UHangulSyllableType */ gcbToHst[]={ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_OTHER */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_CONTROL */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_CR */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_EXTEND */ + HangulSyllableType.LEADING_JAMO, /* U_GCB_L */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_LF */ + HangulSyllableType.LV_SYLLABLE, /* U_GCB_LV */ + HangulSyllableType.LVT_SYLLABLE, /* U_GCB_LVT */ + HangulSyllableType.TRAILING_JAMO, /* U_GCB_T */ + HangulSyllableType.VOWEL_JAMO /* U_GCB_V */ + /* + * Omit GCB values beyond what we need for hst. + * The code below checks for the array length. + */ + }; + + private class IntProperty { + int column; // SRC_PROPSVEC column, or "source" if mask==0 + int mask; + int shift; + + IntProperty(int column, int mask, int shift) { + this.column=column; + this.mask=mask; + this.shift=shift; + } + + IntProperty(int source) { + this.column=source; + this.mask=0; + } + + int getValue(int c) { + // systematic, directly stored properties + return (getAdditional(c, column)&mask)>>>shift; + } + } + + private class BiDiIntProperty extends IntProperty { + BiDiIntProperty() { + super(SRC_BIDI); + } + } + + private class CombiningClassIntProperty extends IntProperty { + CombiningClassIntProperty(int source) { + super(source); + } + } + + private class NormQuickCheckIntProperty extends IntProperty { // UCHAR_NF*_QUICK_CHECK properties + int which; + int max; + + NormQuickCheckIntProperty(int source, int which, int max) { + super(source); + this.which=which; + this.max=max; + } + } + + private IntProperty intProp = new BiDiIntProperty() { // BIDI_PAIRED_BRACKET_TYPE + int getValue(int c) { + return UBiDiProps.INSTANCE.getPairedBracketType(c); + } + }; + + public int getIntPropertyValue(int c, int which) { + if (which == BIDI_PAIRED_BRACKET_TYPE) { + return intProp.getValue(c); + } + return 0; // undefined + } + /** * Forms a supplementary code point from the argument character<br> * Note this is for internal use hence no checks for the validity of the @@ -217,42 +238,48 @@ public final class UCharacterProperty } /** - * Loads the property data and initialize the UCharacterProperty instance. - * @throws MissingResourceException when data is missing or data has been corrupted - */ - public static UCharacterProperty getInstance() + * Gets the type mask + * @param type character type + * @return mask + */ + public static final int getMask(int type) { - if(INSTANCE_ == null) { - try { - INSTANCE_ = new UCharacterProperty(); - } - catch (Exception e) { - throw new MissingResourceException(e.getMessage(),"",""); - } - } - return INSTANCE_; + return 1 << type; } /** - * Checks if the argument c is to be treated as a white space in ICU - * rules. Usually ICU rule white spaces are ignored unless quoted. - * Equivalent to test for Pattern_White_Space Unicode property. - * Stable set of characters, won't change. - * See UAX #31 Identifier and Pattern Syntax: http://www.unicode.org/reports/tr31/ - * @param c codepoint to check - * @return true if c is a ICU white space + * Returns the digit values of characters like 'A' - 'Z', normal, + * half-width and full-width. This method assumes that the other digit + * characters are checked by the calling method. + * @param ch character to test + * @return -1 if ch is not a character of the form 'A' - 'Z', otherwise + * its corresponding digit will be returned. */ - public static boolean isRuleWhiteSpace(int c) - { - /* "white space" in the sense of ICU rule parsers - This is a FIXED LIST that is NOT DEPENDENT ON UNICODE PROPERTIES. - See UAX #31 Identifier and Pattern Syntax: http://www.unicode.org/reports/tr31/ - U+0009..U+000D, U+0020, U+0085, U+200E..U+200F, and U+2028..U+2029 - Equivalent to test for Pattern_White_Space Unicode property. - */ - return (c >= 0x0009 && c <= 0x2029 && - (c <= 0x000D || c == 0x0020 || c == 0x0085 || - c == 0x200E || c == 0x200F || c >= 0x2028)); + public static int getEuropeanDigit(int ch) { + if ((ch > 0x7a && ch < 0xff21) + || ch < 0x41 || (ch > 0x5a && ch < 0x61) + || ch > 0xff5a || (ch > 0xff3a && ch < 0xff41)) { + return -1; + } + if (ch <= 0x7a) { + // ch >= 0x41 or ch < 0x61 + return ch + 10 - ((ch <= 0x5a) ? 0x41 : 0x61); + } + // ch >= 0xff21 + if (ch <= 0xff3a) { + return ch + 10 - 0xff21; + } + // ch >= 0xff41 && ch <= 0xff5a + return ch + 10 - 0xff41; + } + + public int digit(int c) { + int value = getNumericTypeValue(getProperty(c)) - NTV_DECIMAL_START_; + if(value<=9) { + return value; + } else { + return -1; + } } // protected variables ----------------------------------------------- @@ -260,7 +287,7 @@ public final class UCharacterProperty /** * Extra property trie */ - CharTrie m_additionalTrie_; + Trie2_16 m_additionalTrie_; /** * Extra property vectors, 1st column for age and second for binary * properties. @@ -280,40 +307,24 @@ public final class UCharacterProperty * 0 */ int m_maxJTGValue_; + /** + * Script_Extensions data + */ + public char[] m_scriptExtensions_; // private variables ------------------------------------------------- - /** - * UnicodeData.txt property object - */ - private static UCharacterProperty INSTANCE_ = null; - /** * Default name of the datafile */ private static final String DATA_FILE_NAME_ = "/sun/text/resources/uprops.icu"; - /** - * Default buffer size of datafile - */ - private static final int DATA_BUFFER_SIZE_ = 25000; - - /** - * Numeric value shift - */ - private static final int VALUE_SHIFT_ = 8; - - /** - * Mask to be applied after shifting to obtain an unsigned numeric value - */ - private static final int UNSIGNED_VALUE_MASK_AFTER_SHIFT_ = 0xFF; - /** * Shift value for lead surrogate to form a supplementary character. */ private static final int LEAD_SURROGATE_SHIFT_ = 10; /** - * Offset to add to combined surrogate pair to avoid msking. + * Offset to add to combined surrogate pair to avoid masking. */ private static final int SURROGATE_OFFSET_ = UTF16.SUPPLEMENTARY_MIN_VALUE - @@ -321,7 +332,153 @@ public final class UCharacterProperty LEAD_SURROGATE_SHIFT_) - UTF16.TRAIL_SURROGATE_MIN_VALUE; - // additional properties ---------------------------------------------- + + // property data constants ------------------------------------------------- + + /** + * Numeric types and values in the main properties words. + */ + private static final int NUMERIC_TYPE_VALUE_SHIFT_ = 6; + private static final int getNumericTypeValue(int props) { + return props >> NUMERIC_TYPE_VALUE_SHIFT_; + } + + /* constants for the storage form of numeric types and values */ + /** No numeric value. */ + private static final int NTV_NONE_ = 0; + /** Decimal digits: nv=0..9 */ + private static final int NTV_DECIMAL_START_ = 1; + /** Other digits: nv=0..9 */ + private static final int NTV_DIGIT_START_ = 11; + /** Small integers: nv=0..154 */ + private static final int NTV_NUMERIC_START_ = 21; + + private static final int ntvGetType(int ntv) { + return + (ntv==NTV_NONE_) ? NumericType.NONE : + (ntv<NTV_DIGIT_START_) ? NumericType.DECIMAL : + (ntv<NTV_NUMERIC_START_) ? NumericType.DIGIT : + NumericType.NUMERIC; + } + + /* + * Properties in vector word 0 + * Bits + * 31..24 DerivedAge version major/minor one nibble each + * 23..22 3..1: Bits 7..0 = Script_Extensions index + * 3: Script value from Script_Extensions + * 2: Script=Inherited + * 1: Script=Common + * 0: Script=bits 7..0 + * 21..20 reserved + * 19..17 East Asian Width + * 16.. 8 UBlockCode + * 7.. 0 UScriptCode + */ + /** + * Script_Extensions: mask includes Script + */ + public static final int SCRIPT_X_MASK = 0x00c000ff; + //private static final int SCRIPT_X_SHIFT = 22; + /** + * Integer properties mask and shift values for East Asian cell width. + * Equivalent to icu4c UPROPS_EA_MASK + */ + private static final int EAST_ASIAN_MASK_ = 0x000e0000; + /** + * Integer properties mask and shift values for East Asian cell width. + * Equivalent to icu4c UPROPS_EA_SHIFT + */ + private static final int EAST_ASIAN_SHIFT_ = 17; + /** + * Integer properties mask and shift values for blocks. + * Equivalent to icu4c UPROPS_BLOCK_MASK + */ + private static final int BLOCK_MASK_ = 0x0001ff00; + /** + * Integer properties mask and shift values for blocks. + * Equivalent to icu4c UPROPS_BLOCK_SHIFT + */ + private static final int BLOCK_SHIFT_ = 8; + /** + * Integer properties mask and shift values for scripts. + * Equivalent to icu4c UPROPS_SHIFT_MASK + */ + public static final int SCRIPT_MASK_ = 0x000000ff; + + /** + * Additional properties used in internal trie data + */ + /* + * Properties in vector word 1 + * Each bit encodes one binary property. + * The following constants represent the bit number, use 1<<UPROPS_XYZ. + * UPROPS_BINARY_1_TOP<=32! + * + * Keep this list of property enums in sync with + * propListNames[] in icu/source/tools/genprops/props2.c! + * + * ICU 2.6/uprops format version 3.2 stores full properties instead of "Other_". + */ + private static final int WHITE_SPACE_PROPERTY_ = 0; + private static final int DASH_PROPERTY_ = 1; + private static final int HYPHEN_PROPERTY_ = 2; + private static final int QUOTATION_MARK_PROPERTY_ = 3; + private static final int TERMINAL_PUNCTUATION_PROPERTY_ = 4; + private static final int MATH_PROPERTY_ = 5; + private static final int HEX_DIGIT_PROPERTY_ = 6; + private static final int ASCII_HEX_DIGIT_PROPERTY_ = 7; + private static final int ALPHABETIC_PROPERTY_ = 8; + private static final int IDEOGRAPHIC_PROPERTY_ = 9; + private static final int DIACRITIC_PROPERTY_ = 10; + private static final int EXTENDER_PROPERTY_ = 11; + private static final int NONCHARACTER_CODE_POINT_PROPERTY_ = 12; + private static final int GRAPHEME_EXTEND_PROPERTY_ = 13; + private static final int GRAPHEME_LINK_PROPERTY_ = 14; + private static final int IDS_BINARY_OPERATOR_PROPERTY_ = 15; + private static final int IDS_TRINARY_OPERATOR_PROPERTY_ = 16; + private static final int RADICAL_PROPERTY_ = 17; + private static final int UNIFIED_IDEOGRAPH_PROPERTY_ = 18; + private static final int DEFAULT_IGNORABLE_CODE_POINT_PROPERTY_ = 19; + private static final int DEPRECATED_PROPERTY_ = 20; + private static final int LOGICAL_ORDER_EXCEPTION_PROPERTY_ = 21; + private static final int XID_START_PROPERTY_ = 22; + private static final int XID_CONTINUE_PROPERTY_ = 23; + private static final int ID_START_PROPERTY_ = 24; + private static final int ID_CONTINUE_PROPERTY_ = 25; + private static final int GRAPHEME_BASE_PROPERTY_ = 26; + private static final int S_TERM_PROPERTY_ = 27; + private static final int VARIATION_SELECTOR_PROPERTY_ = 28; + private static final int PATTERN_SYNTAX = 29; /* new in ICU 3.4 and Unicode 4.1 */ + private static final int PATTERN_WHITE_SPACE = 30; + + /* + * Properties in vector word 2 + * Bits + * 31..26 reserved + * 25..20 Line Break + * 19..15 Sentence Break + * 14..10 Word Break + * 9.. 5 Grapheme Cluster Break + * 4.. 0 Decomposition Type + */ + private static final int LB_MASK = 0x03f00000; + private static final int LB_SHIFT = 20; + + private static final int SB_MASK = 0x000f8000; + private static final int SB_SHIFT = 15; + + private static final int WB_MASK = 0x00007c00; + private static final int WB_SHIFT = 10; + + private static final int GCB_MASK = 0x000003e0; + private static final int GCB_SHIFT = 5; + + /** + * Integer properties mask for decomposition type. + * Equivalent to icu4c UPROPS_DT_MASK. + */ + private static final int DECOMPOSITION_TYPE_MASK_ = 0x0000001f; /** * First nibble shift @@ -339,31 +496,112 @@ public final class UCharacterProperty // private constructors -------------------------------------------------- /** - * Constructor - * @exception IOException thrown when data reading fails or data corrupted - */ + * Constructor + * @exception IOException thrown when data reading fails or data corrupted + */ private UCharacterProperty() throws IOException { // jar access - InputStream is = ICUData.getRequiredStream(DATA_FILE_NAME_); - BufferedInputStream b = new BufferedInputStream(is, DATA_BUFFER_SIZE_); - UCharacterPropertyReader reader = new UCharacterPropertyReader(b); - reader.read(this); - b.close(); + ByteBuffer bytes=ICUBinary.getRequiredData(DATA_FILE_NAME_); + m_unicodeVersion_ = ICUBinary.readHeaderAndDataVersion(bytes, DATA_FORMAT, new IsAcceptable()); + // Read or skip the 16 indexes. + int propertyOffset = bytes.getInt(); + /* exceptionOffset = */ bytes.getInt(); + /* caseOffset = */ bytes.getInt(); + int additionalOffset = bytes.getInt(); + int additionalVectorsOffset = bytes.getInt(); + m_additionalColumnsCount_ = bytes.getInt(); + int scriptExtensionsOffset = bytes.getInt(); + int reservedOffset7 = bytes.getInt(); + /* reservedOffset8 = */ bytes.getInt(); + /* dataTopOffset = */ bytes.getInt(); + m_maxBlockScriptValue_ = bytes.getInt(); + m_maxJTGValue_ = bytes.getInt(); + ICUBinary.skipBytes(bytes, (16 - 12) << 2); - m_trie_.putIndexData(this); + // read the main properties trie + m_trie_ = Trie2_16.createFromSerialized(bytes); + int expectedTrieLength = (propertyOffset - 16) * 4; + int trieLength = m_trie_.getSerializedLength(); + if(trieLength > expectedTrieLength) { + throw new IOException("uprops.icu: not enough bytes for main trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength - trieLength); + + // skip unused intervening data structures + ICUBinary.skipBytes(bytes, (additionalOffset - propertyOffset) * 4); + + if(m_additionalColumnsCount_ > 0) { + // reads the additional property block + m_additionalTrie_ = Trie2_16.createFromSerialized(bytes); + expectedTrieLength = (additionalVectorsOffset-additionalOffset)*4; + trieLength = m_additionalTrie_.getSerializedLength(); + if(trieLength > expectedTrieLength) { + throw new IOException("uprops.icu: not enough bytes for additional-properties trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength - trieLength); + + // additional properties + int size = scriptExtensionsOffset - additionalVectorsOffset; + m_additionalVectors_ = new int[size]; + for (int i = 0; i < size; i ++) { + m_additionalVectors_[i] = bytes.getInt(); + } + } + + // Script_Extensions + int numChars = (reservedOffset7 - scriptExtensionsOffset) * 2; + if(numChars > 0) { + m_scriptExtensions_ = new char[numChars]; + for(int i = 0; i < numChars; ++i) { + m_scriptExtensions_[i] = bytes.getChar(); + } + } } + private static final class IsAcceptable implements ICUBinary.Authenticate { + // @Override when we switch to Java 6 + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == 7; + } + } + + private static final int DATA_FORMAT = 0x5550726F; // "UPro" + public void upropsvec_addPropertyStarts(UnicodeSet set) { /* add the start code point of each same-value range of the properties vectors trie */ if(m_additionalColumnsCount_>0) { /* if m_additionalColumnsCount_==0 then the properties vectors trie may not be there at all */ - TrieIterator propsVectorsIter = new TrieIterator(m_additionalTrie_); - RangeValueIterator.Element propsVectorsResult = new RangeValueIterator.Element(); - while(propsVectorsIter.next(propsVectorsResult)){ - set.add(propsVectorsResult.start); + Iterator<Trie2.Range> trieIterator = m_additionalTrie_.iterator(); + Trie2.Range range; + while(trieIterator.hasNext() && !(range=trieIterator.next()).leadSurrogate) { + set.add(range.startCodePoint); } } } + // This static initializer block must be placed after + // other static member initialization + static { + try { + INSTANCE = new UCharacterProperty(); + } + catch (IOException e) { + throw new MissingResourceException(e.getMessage(),DATA_FILE_NAME_,""); + } + } + + + // Moved from UProperty.java + /** + * Enumerated property Bidi_Paired_Bracket_Type (new in Unicode 6.3). + * Used in UAX #9: Unicode Bidirectional Algorithm + * (http://www.unicode.org/reports/tr9/) + * Returns UCharacter.BidiPairedBracketType values. + * @stable ICU 52 + */ + public static final int BIDI_PAIRED_BRACKET_TYPE = 0x1015; + } diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterPropertyReader.java b/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterPropertyReader.java deleted file mode 100644 index b0704a9461e..00000000000 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/UCharacterPropertyReader.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. - * 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. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ - -package sun.text.normalizer; - -import java.io.DataInputStream; -import java.io.InputStream; -import java.io.IOException; - -/** -* <p>Internal reader class for ICU data file uprops.icu containing -* Unicode codepoint data.</p> -* <p>This class simply reads uprops.icu, authenticates that it is a valid -* ICU data file and split its contents up into blocks of data for use in -* <a href=UCharacterProperty.html>com.ibm.icu.impl.UCharacterProperty</a>. -* </p> -* <p>uprops.icu which is in big-endian format is jared together with this -* package.</p> -* -* Unicode character properties file format see -* (ICU4C)/source/tools/genprops/store.c -* -* @author Syn Wee Quek -* @since release 2.1, February 1st 2002 -*/ -final class UCharacterPropertyReader implements ICUBinary.Authenticate -{ - // public methods ---------------------------------------------------- - - public boolean isDataVersionAcceptable(byte version[]) - { - return version[0] == DATA_FORMAT_VERSION_[0] - && version[2] == DATA_FORMAT_VERSION_[2] - && version[3] == DATA_FORMAT_VERSION_[3]; - } - - // protected constructor --------------------------------------------- - - /** - * <p>Protected constructor.</p> - * @param inputStream ICU uprop.dat file input stream - * @exception IOException throw if data file fails authentication - */ - protected UCharacterPropertyReader(InputStream inputStream) - throws IOException - { - m_unicodeVersion_ = ICUBinary.readHeader(inputStream, DATA_FORMAT_ID_, - this); - m_dataInputStream_ = new DataInputStream(inputStream); - } - - // protected methods ------------------------------------------------- - - /** - * <p>Reads uprops.icu, parse it into blocks of data to be stored in - * UCharacterProperty.</P - * @param ucharppty UCharacterProperty instance - * @exception IOException thrown when data reading fails - */ - protected void read(UCharacterProperty ucharppty) throws IOException - { - // read the indexes - int count = INDEX_SIZE_; - m_propertyOffset_ = m_dataInputStream_.readInt(); - count --; - m_exceptionOffset_ = m_dataInputStream_.readInt(); - count --; - m_caseOffset_ = m_dataInputStream_.readInt(); - count --; - m_additionalOffset_ = m_dataInputStream_.readInt(); - count --; - m_additionalVectorsOffset_ = m_dataInputStream_.readInt(); - count --; - m_additionalColumnsCount_ = m_dataInputStream_.readInt(); - count --; - m_reservedOffset_ = m_dataInputStream_.readInt(); - count --; - m_dataInputStream_.skipBytes(3 << 2); - count -= 3; - ucharppty.m_maxBlockScriptValue_ = m_dataInputStream_.readInt(); - count --; // 10 - ucharppty.m_maxJTGValue_ = m_dataInputStream_.readInt(); - count --; // 11 - m_dataInputStream_.skipBytes(count << 2); - - // read the trie index block - // m_props_index_ in terms of ints - ucharppty.m_trie_ = new CharTrie(m_dataInputStream_, null); - - // skip the 32 bit properties block - int size = m_exceptionOffset_ - m_propertyOffset_; - m_dataInputStream_.skipBytes(size * 4); - - // reads the 32 bit exceptions block - size = m_caseOffset_ - m_exceptionOffset_; - m_dataInputStream_.skipBytes(size * 4); - - // reads the 32 bit case block - size = (m_additionalOffset_ - m_caseOffset_) << 1; - m_dataInputStream_.skipBytes(size * 2); - - if(m_additionalColumnsCount_ > 0) { - // reads the additional property block - ucharppty.m_additionalTrie_ = new CharTrie(m_dataInputStream_, null); - - // additional properties - size = m_reservedOffset_ - m_additionalVectorsOffset_; - ucharppty.m_additionalVectors_ = new int[size]; - for (int i = 0; i < size; i ++) { - ucharppty.m_additionalVectors_[i] = m_dataInputStream_.readInt(); - } - } - - m_dataInputStream_.close(); - ucharppty.m_additionalColumnsCount_ = m_additionalColumnsCount_; - ucharppty.m_unicodeVersion_ = VersionInfo.getInstance( - (int)m_unicodeVersion_[0], (int)m_unicodeVersion_[1], - (int)m_unicodeVersion_[2], (int)m_unicodeVersion_[3]); - } - - // private variables ------------------------------------------------- - - /** - * Index size - */ - private static final int INDEX_SIZE_ = 16; - - /** - * ICU data file input stream - */ - private DataInputStream m_dataInputStream_; - - /** - * Offset information in the indexes. - */ - private int m_propertyOffset_; - private int m_exceptionOffset_; - private int m_caseOffset_; - private int m_additionalOffset_; - private int m_additionalVectorsOffset_; - private int m_additionalColumnsCount_; - private int m_reservedOffset_; - private byte m_unicodeVersion_[]; - - /** - * Data format "UPro". - */ - private static final byte DATA_FORMAT_ID_[] = {(byte)0x55, (byte)0x50, - (byte)0x72, (byte)0x6F}; - /** - * Format version; this code works with all versions with the same major - * version number and the same Trie bit distribution. - */ - private static final byte DATA_FORMAT_VERSION_[] = {(byte)0x5, (byte)0, - (byte)Trie.INDEX_STAGE_1_SHIFT_, - (byte)Trie.INDEX_STAGE_2_SHIFT_}; -} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/UTF16.java b/jdk/src/java.base/share/classes/sun/text/normalizer/UTF16.java index f705364b1c8..c032eb2ceb7 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/UTF16.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/UTF16.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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,15 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -/* +/** ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. ******************************************************************************* */ @@ -57,21 +52,21 @@ package sun.text.normalizer; * * // iteration forwards: Changes for UTF-32 * int ch; - * for (int i = 0; i < s.length(); i+=UTF16.getCharCount(ch)) { - * ch = UTF16.charAt(s,i); + * for (int i = 0; i < s.length(); i += UTF16.getCharCount(ch)) { + * ch = UTF16.charAt(s, i); * doSomethingWith(ch); * } * * // iteration backwards: Original - * for (int i = s.length() -1; i >= 0; --i) { + * for (int i = s.length() - 1; i >= 0; --i) { * char ch = s.charAt(i); * doSomethingWith(ch); * } * * // iteration backwards: Changes for UTF-32 * int ch; - * for (int i = s.length() -1; i > 0; i-=UTF16.getCharCount(ch)) { - * ch = UTF16.charAt(s,i); + * for (int i = s.length() - 1; i > 0; i -= UTF16.getCharCount(ch)) { + * ch = UTF16.charAt(s, i); * doSomethingWith(ch); * } * }</pre> @@ -93,7 +88,7 @@ package sun.text.normalizer; * back if and only if <code>bounds(string, offset16) != TRAIL</code>. * </li> * <li> - * <strong>Exceptions:</strong> The error checking will throw an exception + * <strong>Exceptions:</strong> The error checking will throw an exception * if indices are out of bounds. Other than that, all methods will * behave reasonably, even if unmatched surrogates or out-of-bounds UTF-32 * values are present. <code>UCharacter.isLegal()</code> can be used to check @@ -106,10 +101,10 @@ package sun.text.normalizer; * practice as missing glyphs (see the Unicode Standard Section 5.4, 5.5). * </li> * <li> - * <strong>Optimization:</strong> The method implementations may need - * optimization if the compiler doesn't fold static final methods. Since - * surrogate pairs will form an exceeding small percentage of all the text - * in the world, the singleton case should always be optimized for. + * <strong>Optimization:</strong> The method implementations may need + * optimization if the compiler doesn't fold static final methods. Since + * surrogate pairs will form an exceeding small percentage of all the text + * in the world, the singleton case should always be optimized for. * </li> * </ul> * @author Mark Davis, with help from Markus Scherer @@ -135,7 +130,7 @@ public final class UTF16 * The minimum value for Supplementary code points * @stable ICU 2.1 */ - public static final int SUPPLEMENTARY_MIN_VALUE = 0x10000; + public static final int SUPPLEMENTARY_MIN_VALUE = 0x10000; /** * Lead surrogate minimum value * @stable ICU 2.1 @@ -161,7 +156,41 @@ public final class UTF16 * @stable ICU 2.1 */ public static final int SURROGATE_MIN_VALUE = LEAD_SURROGATE_MIN_VALUE; + /** + * Lead surrogate bitmask + */ + private static final int LEAD_SURROGATE_BITMASK = 0xFFFFFC00; + /** + * Trail surrogate bitmask + */ + private static final int TRAIL_SURROGATE_BITMASK = 0xFFFFFC00; + /** + * Surrogate bitmask + */ + private static final int SURROGATE_BITMASK = 0xFFFFF800; + /** + * Lead surrogate bits + */ + private static final int LEAD_SURROGATE_BITS = 0xD800; + /** + * Trail surrogate bits + */ + private static final int TRAIL_SURROGATE_BITS = 0xDC00; + /** + * Surrogate bits + */ + private static final int SURROGATE_BITS = 0xD800; + // constructor -------------------------------------------------------- + + // /CLOVER:OFF + /** + * Prevent instance from being created. + */ + private UTF16() { + } + + // /CLOVER:ON // public method ------------------------------------------------------ /** @@ -222,7 +251,7 @@ public final class UTF16 } /** - * Extract a single UTF-32 value from a substring. + * Extract a single UTF-32 value from a string. * Used when iterating forwards or backwards (with * <code>UTF16.getCharCount()</code>, as well as random access. If a * validity check is required, use @@ -232,19 +261,72 @@ public final class UTF16 * character will be returned. If a complete supplementary character is * not found the incomplete character will be returned * @param source array of UTF-16 chars - * @param start offset to substring in the source array for analyzing - * @param limit offset to substring in the source array for analyzing - * @param offset16 UTF-16 offset relative to start + * @param offset16 UTF-16 offset to the start of the character. * @return UTF-32 value for the UTF-32 value that contains the char at * offset16. The boundaries of that codepoint are the same as in * <code>bounds32()</code>. - * @exception IndexOutOfBoundsException thrown if offset16 is not within - * the range of start and limit. + * @exception IndexOutOfBoundsException thrown if offset16 is out of bounds. * @stable ICU 2.1 */ - public static int charAt(char source[], int start, int limit, - int offset16) - { + public static int charAt(CharSequence source, int offset16) { + char single = source.charAt(offset16); + if (single < UTF16.LEAD_SURROGATE_MIN_VALUE) { + return single; + } + return _charAt(source, offset16, single); + } + + private static int _charAt(CharSequence source, int offset16, char single) { + if (single > UTF16.TRAIL_SURROGATE_MAX_VALUE) { + return single; + } + + // Convert the UTF-16 surrogate pair if necessary. + // For simplicity in usage, and because the frequency of pairs is + // low, look both directions. + + if (single <= UTF16.LEAD_SURROGATE_MAX_VALUE) { + ++offset16; + if (source.length() != offset16) { + char trail = source.charAt(offset16); + if (trail >= UTF16.TRAIL_SURROGATE_MIN_VALUE + && trail <= UTF16.TRAIL_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(single, trail); + } + } + } else { + --offset16; + if (offset16 >= 0) { + // single is a trail surrogate so + char lead = source.charAt(offset16); + if (lead >= UTF16.LEAD_SURROGATE_MIN_VALUE + && lead <= UTF16.LEAD_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(lead, single); + } + } + } + return single; // return unmatched surrogate + } + + /** + * Extract a single UTF-32 value from a substring. Used when iterating forwards or backwards + * (with <code>UTF16.getCharCount()</code>, as well as random access. If a validity check is + * required, use <code><a href="../lang/UCharacter.html#isLegal(char)">UCharacter.isLegal() + * </a></code> + * on the return value. If the char retrieved is part of a surrogate pair, its supplementary + * character will be returned. If a complete supplementary character is not found the incomplete + * character will be returned + * + * @param source Array of UTF-16 chars + * @param start Offset to substring in the source array for analyzing + * @param limit Offset to substring in the source array for analyzing + * @param offset16 UTF-16 offset relative to start + * @return UTF-32 value for the UTF-32 value that contains the char at offset16. The boundaries + * of that codepoint are the same as in <code>bounds32()</code>. + * @exception IndexOutOfBoundsException Thrown if offset16 is not within the range of start and limit. + * @stable ICU 2.1 + */ + public static int charAt(char source[], int start, int limit, int offset16) { offset16 += start; if (offset16 < start || offset16 >= limit) { throw new ArrayIndexOutOfBoundsException(offset16); @@ -259,7 +341,7 @@ public final class UTF16 // For simplicity in usage, and because the frequency of pairs is // low, look both directions. if (single <= LEAD_SURROGATE_MAX_VALUE) { - offset16 ++; + offset16++; if (offset16 >= limit) { return single; } @@ -272,7 +354,7 @@ public final class UTF16 if (offset16 == start) { return single; } - offset16 --; + offset16--; char lead = source[offset16]; if (isLeadSurrogate(lead)) return UCharacterProperty.getRawSupplementary(lead, single); @@ -300,37 +382,34 @@ public final class UTF16 /** * Determines whether the code value is a surrogate. * @param char16 the input character. - * @return true iff the input character is a surrogate. + * @return true if the input character is a surrogate. * @stable ICU 2.1 */ public static boolean isSurrogate(char char16) { - return LEAD_SURROGATE_MIN_VALUE <= char16 && - char16 <= TRAIL_SURROGATE_MAX_VALUE; + return (char16 & SURROGATE_BITMASK) == SURROGATE_BITS; } /** * Determines whether the character is a trail surrogate. * @param char16 the input character. - * @return true iff the input character is a trail surrogate. + * @return true if the input character is a trail surrogate. * @stable ICU 2.1 */ public static boolean isTrailSurrogate(char char16) { - return (TRAIL_SURROGATE_MIN_VALUE <= char16 && - char16 <= TRAIL_SURROGATE_MAX_VALUE); + return (char16 & TRAIL_SURROGATE_BITMASK) == TRAIL_SURROGATE_BITS; } /** * Determines whether the character is a lead surrogate. * @param char16 the input character. - * @return true iff the input character is a lead surrogate + * @return true if the input character is a lead surrogate * @stable ICU 2.1 */ public static boolean isLeadSurrogate(char char16) { - return LEAD_SURROGATE_MIN_VALUE <= char16 && - char16 <= LEAD_SURROGATE_MAX_VALUE; + return (char16 & LEAD_SURROGATE_BITMASK) == LEAD_SURROGATE_BITS; } /** @@ -359,7 +438,7 @@ public final class UTF16 * <code><a href="../lang/UCharacter.html#isLegal(char)">isLegal()</a></code> * on char32 before calling. * @param char32 the input character. - * @return the trail surrogate if the getCharCount(ch) is 2; <br>otherwise + * @return the trail surrogate if the getCharCount(ch) is 2; <br> otherwise * the character itself * @stable ICU 2.1 */ @@ -370,7 +449,7 @@ public final class UTF16 (char32 & TRAIL_SURROGATE_MASK_)); } - return (char)char32; + return (char) char32; } /** @@ -415,16 +494,15 @@ public final class UTF16 // Write the UTF-16 values if (char32 >= SUPPLEMENTARY_MIN_VALUE) { - target.append(getLeadSurrogate(char32)); - target.append(getTrailSurrogate(char32)); - } + target.append(getLeadSurrogate(char32)); + target.append(getTrailSurrogate(char32)); + } else { - target.append((char)char32); + target.append((char) char32); } return target; } - //// for StringPrep /** * Shifts offset16 by the argument number of codepoints within a subarray. * @param source char array @@ -441,20 +519,20 @@ public final class UTF16 public static int moveCodePointOffset(char source[], int start, int limit, int offset16, int shift32) { - int size = source.length; - int count; - char ch; - int result = offset16 + start; - if (start<0 || limit<start) { + int size = source.length; + int count; + char ch; + int result = offset16 + start; + if (start < 0 || limit < start) { throw new StringIndexOutOfBoundsException(start); } - if (limit>size) { + if (limit > size) { throw new StringIndexOutOfBoundsException(limit); } - if (offset16<0 || result>limit) { + if (offset16 < 0 || result > limit) { throw new StringIndexOutOfBoundsException(offset16); } - if (shift32 > 0 ) { + if (shift32 > 0) { if (shift32 + result > size) { throw new StringIndexOutOfBoundsException(result); } @@ -462,29 +540,29 @@ public final class UTF16 while (result < limit && count > 0) { ch = source[result]; - if (isLeadSurrogate(ch) && (result+1 < limit) && - isTrailSurrogate(source[result+1])) { - result ++; + if (isLeadSurrogate(ch) && (result + 1 < limit) && + isTrailSurrogate(source[result + 1])) { + result++; } - count --; - result ++; + count--; + result++; } } else { if (result + shift32 < start) { throw new StringIndexOutOfBoundsException(result); } - for (count=-shift32; count>0; count--) { + for (count = -shift32; count > 0; count--) { result--; - if (result<start) { + if (result < start) { break; } ch = source[result]; - if (isTrailSurrogate(ch) && result>start && isLeadSurrogate(source[result-1])) { + if (isTrailSurrogate(ch) && result > start && isLeadSurrogate(source[result - 1])) { result--; } } } - if (count != 0) { + if (count != 0) { throw new StringIndexOutOfBoundsException(shift32); } result -= start; @@ -501,7 +579,7 @@ public final class UTF16 /** * Mask to retrieve the significant value from a trail surrogate. */ - private static final int TRAIL_SURROGATE_MASK_ = 0x3FF; + private static final int TRAIL_SURROGATE_MASK_ = 0x3FF; /** * Value that all lead surrogate starts with @@ -509,7 +587,7 @@ public final class UTF16 private static final int LEAD_SURROGATE_OFFSET_ = LEAD_SURROGATE_MIN_VALUE - (SUPPLEMENTARY_MIN_VALUE - >> LEAD_SURROGATE_SHIFT_); + >> LEAD_SURROGATE_SHIFT_); // private methods ------------------------------------------------------ @@ -527,7 +605,7 @@ public final class UTF16 private static String toString(int ch) { if (ch < SUPPLEMENTARY_MIN_VALUE) { - return String.valueOf((char)ch); + return String.valueOf((char) ch); } StringBuilder result = new StringBuilder(); diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSet.java b/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSet.java index 3fcd67466b7..a2072698bba 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSet.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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,29 +22,31 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * + * Copyright (C) 1996-2015, International Business Machines Corporation and + * others. All Rights Reserved. ******************************************************************************* */ - package sun.text.normalizer; +import java.io.IOException; import java.text.ParsePosition; -import java.util.Iterator; +import java.util.ArrayList; import java.util.TreeSet; /** - * A mutable set of Unicode characters and multicharacter strings. Objects of this class - * represent <em>character classes</em> used in regular expressions. - * A character specifies a subset of Unicode code points. Legal - * code points are U+0000 to U+10FFFF, inclusive. + * A mutable set of Unicode characters and multicharacter strings. + * Objects of this class represent <em>character classes</em> used + * in regular expressions. A character specifies a subset of Unicode + * code points. Legal code points are U+0000 to U+10FFFF, inclusive. + * + * Note: method freeze() will not only make the set immutable, but + * also makes important methods much higher performance: + * contains(c), containsNone(...), span(...), spanBack(...) etc. + * After the object is frozen, any subsequent call that wants to change + * the object will throw UnsupportedOperationException. * * <p>The UnicodeSet class is not designed to be subclassed. * @@ -118,7 +120,7 @@ import java.util.TreeSet; * </blockquote> * * Any character may be preceded by a backslash in order to remove any special - * meaning. White space characters, as defined by UCharacterProperty.isRuleWhiteSpace(), are + * meaning. White space characters, as defined by the Unicode Pattern_White_Space property, are * ignored, unless they are escaped. * * <p>Property patterns specify a set of characters having a certain @@ -267,18 +269,24 @@ import java.util.TreeSet; * </tr> * </table> * </blockquote> - * <p>To iterate over contents of UnicodeSet, use UnicodeSetIterator class. + * <p>To iterate over contents of UnicodeSet, the following are available: + * <ul><li>{@link #ranges()} to iterate through the ranges</li> + * <li>{@link #strings()} to iterate through the strings</li> + * <li>{@link #iterator()} to iterate through the entire contents in a single loop. + * That method is, however, not particularly efficient, since it "boxes" each code point into a String. + * </ul> + * All of the above can be used in <b>for</b> loops. + * The {@link com.ibm.icu.text.UnicodeSetIterator UnicodeSetIterator} can also be used, but not in <b>for</b> loops. + * <p>To replace, count elements, or delete spans, see {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. * * @author Alan Liu * @stable ICU 2.0 - * @see UnicodeSetIterator */ -@SuppressWarnings("deprecation") -public class UnicodeSet implements UnicodeMatcher { +class UnicodeSet { 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. - // 110000 for codepoints + // 110000 for codepoints /** * Minimum value that can be stored in a UnicodeSet. @@ -299,7 +307,7 @@ public class UnicodeSet implements UnicodeMatcher { // NOTE: normally the field should be of type SortedSet; but that is missing a public clone!! // is not private so that UnicodeSetIterator can get access - TreeSet<String> strings = new TreeSet<>(); + TreeSet<String> strings = new TreeSet<String>(); /** * The pattern representation of this set. This may not be the @@ -310,18 +318,14 @@ public class UnicodeSet implements UnicodeMatcher { * indicating that toPattern() must generate a pattern * representation from the inversion list. */ - private String pat = null; private static final int START_EXTRA = 16; // initial storage. Must be >= 0 private static final int GROW_EXTRA = START_EXTRA; // extra amount for growth. Must be >= 0 - /** - * A set of all characters _except_ the second through last characters of - * certain ranges. These ranges are ranges of characters whose - * properties are all exactly alike, e.g. CJK Ideographs from - * U+4E00 to U+9FA5. - */ - private static UnicodeSet INCLUSIONS[] = null; + private static UnicodeSet INCLUSION = null; + + private volatile BMPSet bmpSet; // The set is frozen if bmpSet or stringSpan is not null. + private volatile UnicodeSetStringSpan stringSpan; //---------------------------------------------------------------- // Public API @@ -331,14 +335,22 @@ public class UnicodeSet implements UnicodeMatcher { * Constructs an empty set. * @stable ICU 2.0 */ - public UnicodeSet() { + private UnicodeSet() { list = new int[1 + START_EXTRA]; list[len++] = HIGH; } /** - * Constructs a set containing the given range. - * If {@code end > start} then an empty set is created. + * Constructs a copy of an existing set. + * @stable ICU 2.0 + */ + private UnicodeSet(UnicodeSet other) { + set(other); + } + + /** + * Constructs a set containing the given range. If <code>end > + * start</code> then an empty set is created. * * @param start first character, inclusive, of range * @param end last character, inclusive, of range @@ -359,7 +371,7 @@ public class UnicodeSet implements UnicodeMatcher { */ public UnicodeSet(String pattern) { this(); - applyPattern(pattern, null, null, IGNORE_SPACE); + applyPattern(pattern, null); } /** @@ -368,172 +380,29 @@ public class UnicodeSet implements UnicodeMatcher { * copied to this object * @stable ICU 2.0 */ - @SuppressWarnings("unchecked") // Casting result of clone of a collection public UnicodeSet set(UnicodeSet other) { + checkFrozen(); list = other.list.clone(); len = other.len; - pat = other.pat; - strings = (TreeSet)other.strings.clone(); + strings = new TreeSet<String>(other.strings); return this; } /** - * Modifies this set to represent the set specified by the given pattern. - * See the class description for the syntax of the pattern language. - * Whitespace is ignored. - * @param pattern a string specifying what characters are in the set - * @exception java.lang.IllegalArgumentException if the pattern - * contains a syntax error. + * Returns the number of elements in this set (its cardinality) + * Note than the elements of a set may include both individual + * codepoints and strings. + * + * @return the number of elements in this set (its cardinality). * @stable ICU 2.0 */ - public final UnicodeSet applyPattern(String pattern) { - return applyPattern(pattern, null, null, IGNORE_SPACE); - } - - /** - * Append the <code>toPattern()</code> representation of a - * string to the given <code>StringBuffer</code>. - */ - private static void _appendToPat(StringBuffer buf, String s, boolean escapeUnprintable) { - for (int i = 0; i < s.length(); i += UTF16.getCharCount(i)) { - _appendToPat(buf, UTF16.charAt(s, i), escapeUnprintable); - } - } - - /** - * Append the <code>toPattern()</code> representation of a - * character to the given <code>StringBuffer</code>. - */ - private static void _appendToPat(StringBuffer buf, int c, boolean escapeUnprintable) { - if (escapeUnprintable && Utility.isUnprintable(c)) { - // Use hex escape notation (<backslash>uxxxx or <backslash>Uxxxxxxxx) for anything - // unprintable - if (Utility.escapeUnprintable(buf, c)) { - return; - } - } - // Okay to let ':' pass through - switch (c) { - case '[': // SET_OPEN: - case ']': // SET_CLOSE: - case '-': // HYPHEN: - case '^': // COMPLEMENT: - case '&': // INTERSECTION: - case '\\': //BACKSLASH: - case '{': - case '}': - case '$': - case ':': - buf.append('\\'); - break; - default: - // Escape whitespace - if (UCharacterProperty.isRuleWhiteSpace(c)) { - buf.append('\\'); - } - break; - } - UTF16.append(buf, c); - } - - /** - * Append a string representation of this set to result. This will be - * a cleaned version of the string passed to applyPattern(), if there - * is one. Otherwise it will be generated. - */ - private StringBuffer _toPattern(StringBuffer result, - boolean escapeUnprintable) { - if (pat != null) { - int i; - int backslashCount = 0; - for (i=0; i<pat.length(); ) { - int c = UTF16.charAt(pat, i); - i += UTF16.getCharCount(c); - if (escapeUnprintable && Utility.isUnprintable(c)) { - // If the unprintable character is preceded by an odd - // number of backslashes, then it has been escaped. - // Before unescaping it, we delete the final - // backslash. - if ((backslashCount % 2) == 1) { - result.setLength(result.length() - 1); - } - Utility.escapeUnprintable(result, c); - backslashCount = 0; - } else { - UTF16.append(result, c); - if (c == '\\') { - ++backslashCount; - } else { - backslashCount = 0; - } - } - } - return result; - } - - return _generatePattern(result, escapeUnprintable, true); - } - - /** - * Generate and append a string representation of this set to result. - * This does not use this.pat, the cleaned up copy of the string - * passed to applyPattern(). - * @param includeStrings if false, doesn't include the strings. - * @stable ICU 3.8 - */ - public StringBuffer _generatePattern(StringBuffer result, - boolean escapeUnprintable, boolean includeStrings) { - result.append('['); - + public int size() { + int n = 0; int count = getRangeCount(); - - // If the set contains at least 2 intervals and includes both - // MIN_VALUE and MAX_VALUE, then the inverse representation will - // be more economical. - if (count > 1 && - getRangeStart(0) == MIN_VALUE && - getRangeEnd(count-1) == MAX_VALUE) { - - // Emit the inverse - result.append('^'); - - for (int i = 1; i < count; ++i) { - int start = getRangeEnd(i-1)+1; - int end = getRangeStart(i)-1; - _appendToPat(result, start, escapeUnprintable); - if (start != end) { - if ((start+1) != end) { - result.append('-'); - } - _appendToPat(result, end, escapeUnprintable); - } - } + for (int i = 0; i < count; ++i) { + n += getRangeEnd(i) - getRangeStart(i) + 1; } - - // Default; emit the ranges as pairs - else { - for (int i = 0; i < count; ++i) { - int start = getRangeStart(i); - int end = getRangeEnd(i); - _appendToPat(result, start, escapeUnprintable); - if (start != end) { - if ((start+1) != end) { - result.append('-'); - } - _appendToPat(result, end, escapeUnprintable); - } - } - } - - if (includeStrings && strings.size() > 0) { - Iterator<String> it = strings.iterator(); - while (it.hasNext()) { - result.append('{'); - _appendToPat(result, it.next(), escapeUnprintable); - result.append('}'); - } - } - return result.append(']'); + return n + strings.size(); } // for internal use, after checkFrozen has been called @@ -559,6 +428,7 @@ public class UnicodeSet implements UnicodeMatcher { * @stable ICU 2.0 */ public final UnicodeSet add(int c) { + checkFrozen(); return add_unchecked(c); } @@ -643,7 +513,6 @@ public class UnicodeSet implements UnicodeMatcher { len += 2; } - pat = null; return this; } @@ -657,11 +526,11 @@ public class UnicodeSet implements UnicodeMatcher { * @return this object, for chaining * @stable ICU 2.0 */ - public final UnicodeSet add(String s) { + public final UnicodeSet add(CharSequence s) { + checkFrozen(); int cp = getSingleCP(s); if (cp < 0) { - strings.add(s); - pat = null; + strings.add(s.toString()); } else { add_unchecked(cp, cp); } @@ -669,11 +538,13 @@ public class UnicodeSet implements UnicodeMatcher { } /** + * Utility for getting code point from single code point CharSequence. + * See the public UTF16.getSingleCodePoint() * @return a code point IF the string consists of a single one. * otherwise returns -1. - * @param string to test + * @param s to test */ - private static int getSingleCP(String s) { + private static int getSingleCP(CharSequence s) { if (s.length() < 1) { throw new IllegalArgumentException("Can't use zero-length strings in UnicodeSet"); } @@ -701,6 +572,7 @@ public class UnicodeSet implements UnicodeMatcher { * @stable ICU 2.0 */ public UnicodeSet complement(int start, int end) { + checkFrozen(); if (start < MIN_VALUE || start > MAX_VALUE) { throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(start, 6)); } @@ -710,26 +582,6 @@ public class UnicodeSet implements UnicodeMatcher { if (start <= end) { xor(range(start, end), 2, 0); } - pat = null; - return this; - } - - /** - * This is equivalent to - * <code>complement(MIN_VALUE, MAX_VALUE)</code>. - * @stable ICU 2.0 - */ - public UnicodeSet complement() { - if (list[0] == LOW) { - System.arraycopy(list, 1, list, 0, len-1); - --len; - } else { - ensureCapacity(len+1); - System.arraycopy(list, 0, list, 1, len); - list[0] = LOW; - ++len; - } - pat = null; return this; } @@ -743,6 +595,12 @@ public class UnicodeSet implements UnicodeMatcher { if (c < MIN_VALUE || c > MAX_VALUE) { throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(c, 6)); } + if (bmpSet != null) { + return bmpSet.contains(c); + } + if (stringSpan != null) { + return stringSpan.contains(c); + } /* // Set i to the index of the start item greater than ch @@ -751,7 +609,7 @@ public class UnicodeSet implements UnicodeMatcher { while (true) { if (c < list[++i]) break; } - */ + */ int i = findCodePoint(c); @@ -790,7 +648,7 @@ public class UnicodeSet implements UnicodeMatcher { // invariant: c < list[hi] for (;;) { int i = (lo + hi) >>> 1; - if (i == lo) return hi; + if (i == lo) return hi; if (c < list[i]) { hi = i; } else { @@ -799,22 +657,6 @@ public class UnicodeSet implements UnicodeMatcher { } } - /** - * Adds all of the elements in the specified set to this set if - * they're not already present. This operation effectively - * modifies this set so that its value is the <i>union</i> of the two - * sets. The behavior of this operation is unspecified if the specified - * collection is modified while the operation is in progress. - * - * @param c set whose elements are to be added to this set. - * @stable ICU 2.0 - */ - public UnicodeSet addAll(UnicodeSet c) { - add(c.list, c.len, 0); - strings.addAll(c.strings); - return this; - } - /** * Retains only the elements in this set that are contained in the * specified set. In other words, removes from this set all of @@ -826,36 +668,21 @@ public class UnicodeSet implements UnicodeMatcher { * @stable ICU 2.0 */ public UnicodeSet retainAll(UnicodeSet c) { + checkFrozen(); retain(c.list, c.len, 0); strings.retainAll(c.strings); return this; } - /** - * Removes from this set all of its elements that are contained in the - * specified set. This operation effectively modifies this - * set so that its value is the <i>asymmetric set difference</i> of - * the two sets. - * - * @param c set that defines which elements will be removed from - * this set. - * @stable ICU 2.0 - */ - public UnicodeSet removeAll(UnicodeSet c) { - retain(c.list, c.len, 2); - strings.removeAll(c.strings); - return this; - } - /** * Removes all of the elements from this set. This set will be * empty after this call returns. * @stable ICU 2.0 */ public UnicodeSet clear() { + checkFrozen(); list[0] = HIGH; len = 1; - pat = null; strings.clear(); return this; } @@ -923,405 +750,18 @@ public class UnicodeSet implements UnicodeMatcher { * of <code>pattern</code> * @exception java.lang.IllegalArgumentException if the parse fails. */ - UnicodeSet applyPattern(String pattern, - ParsePosition pos, - SymbolTable symbols, - int options) { - - // Need to build the pattern in a temporary string because - // _applyPattern calls add() etc., which set pat to empty. - boolean parsePositionWasNull = pos == null; - if (parsePositionWasNull) { - pos = new ParsePosition(0); - } - - StringBuffer rebuiltPat = new StringBuffer(); - RuleCharacterIterator chars = - new RuleCharacterIterator(pattern, symbols, pos); - applyPattern(chars, symbols, rebuiltPat, options); - if (chars.inVariable()) { - syntaxError(chars, "Extra chars in variable value"); - } - pat = rebuiltPat.toString(); - if (parsePositionWasNull) { - int i = pos.getIndex(); - - // Skip over trailing whitespace - if ((options & IGNORE_SPACE) != 0) { - i = Utility.skipWhitespace(pattern, i); - } - - if (i != pattern.length()) { - throw new IllegalArgumentException("Parse of \"" + pattern + - "\" failed at " + i); - } - } - return this; - } - - /** - * Parse the pattern from the given RuleCharacterIterator. The - * iterator is advanced over the parsed pattern. - * @param chars iterator over the pattern characters. Upon return - * it will be advanced to the first character after the parsed - * pattern, or the end of the iteration if all characters are - * parsed. - * @param symbols symbol table to use to parse and dereference - * variables, or null if none. - * @param rebuiltPat the pattern that was parsed, rebuilt or - * copied from the input pattern, as appropriate. - * @param options a bit mask of zero or more of the following: - * IGNORE_SPACE, CASE. - */ - void applyPattern(RuleCharacterIterator chars, SymbolTable symbols, - StringBuffer rebuiltPat, int options) { - // Syntax characters: [ ] ^ - & { } - - // Recognized special forms for chars, sets: c-c s-s s&s - - int opts = RuleCharacterIterator.PARSE_VARIABLES | - RuleCharacterIterator.PARSE_ESCAPES; - if ((options & IGNORE_SPACE) != 0) { - opts |= RuleCharacterIterator.SKIP_WHITESPACE; - } - - StringBuffer patBuf = new StringBuffer(), buf = null; - boolean usePat = false; - UnicodeSet scratch = null; - Object backup = null; - - // mode: 0=before [, 1=between [...], 2=after ] - // lastItem: 0=none, 1=char, 2=set - int lastItem = 0, lastChar = 0, mode = 0; - char op = 0; - - boolean invert = false; - - clear(); - - while (mode != 2 && !chars.atEnd()) { - if (false) { - // Debugging assertion - if (!((lastItem == 0 && op == 0) || - (lastItem == 1 && (op == 0 || op == '-')) || - (lastItem == 2 && (op == 0 || op == '-' || op == '&')))) { - throw new IllegalArgumentException(); - } - } - - int c = 0; - boolean literal = false; - UnicodeSet nested = null; - - // -------- Check for property pattern - - // setMode: 0=none, 1=unicodeset, 2=propertypat, 3=preparsed - int setMode = 0; - if (resemblesPropertyPattern(chars, opts)) { - setMode = 2; - } - - // -------- Parse '[' of opening delimiter OR nested set. - // If there is a nested set, use `setMode' to define how - // the set should be parsed. If the '[' is part of the - // opening delimiter for this pattern, parse special - // strings "[", "[^", "[-", and "[^-". Check for stand-in - // characters representing a nested set in the symbol - // table. - - else { - // Prepare to backup if necessary - backup = chars.getPos(backup); - c = chars.next(opts); - literal = chars.isEscaped(); - - if (c == '[' && !literal) { - if (mode == 1) { - chars.setPos(backup); // backup - setMode = 1; - } else { - // Handle opening '[' delimiter - mode = 1; - patBuf.append('['); - backup = chars.getPos(backup); // prepare to backup - c = chars.next(opts); - literal = chars.isEscaped(); - if (c == '^' && !literal) { - invert = true; - patBuf.append('^'); - backup = chars.getPos(backup); // prepare to backup - c = chars.next(opts); - literal = chars.isEscaped(); - } - // Fall through to handle special leading '-'; - // otherwise restart loop for nested [], \p{}, etc. - if (c == '-') { - literal = true; - // Fall through to handle literal '-' below - } else { - chars.setPos(backup); // backup - continue; - } - } - } else if (symbols != null) { - UnicodeMatcher m = symbols.lookupMatcher(c); // may be null - if (m != null) { - try { - nested = (UnicodeSet) m; - setMode = 3; - } catch (ClassCastException e) { - syntaxError(chars, "Syntax error"); - } - } - } - } - - // -------- Handle a nested set. This either is inline in - // the pattern or represented by a stand-in that has - // previously been parsed and was looked up in the symbol - // table. - - if (setMode != 0) { - if (lastItem == 1) { - if (op != 0) { - syntaxError(chars, "Char expected after operator"); - } - add_unchecked(lastChar, lastChar); - _appendToPat(patBuf, lastChar, false); - lastItem = op = 0; - } - - if (op == '-' || op == '&') { - patBuf.append(op); - } - - if (nested == null) { - if (scratch == null) scratch = new UnicodeSet(); - nested = scratch; - } - switch (setMode) { - case 1: - nested.applyPattern(chars, symbols, patBuf, options); - break; - case 2: - chars.skipIgnored(opts); - nested.applyPropertyPattern(chars, patBuf, symbols); - break; - case 3: // `nested' already parsed - nested._toPattern(patBuf, false); - break; - } - - usePat = true; - - if (mode == 0) { - // Entire pattern is a category; leave parse loop - set(nested); - mode = 2; - break; - } - - switch (op) { - case '-': - removeAll(nested); - break; - case '&': - retainAll(nested); - break; - case 0: - addAll(nested); - break; - } - - op = 0; - lastItem = 2; - - continue; - } - - if (mode == 0) { - syntaxError(chars, "Missing '['"); - } - - // -------- Parse special (syntax) characters. If the - // current character is not special, or if it is escaped, - // then fall through and handle it below. - - if (!literal) { - switch (c) { - case ']': - if (lastItem == 1) { - add_unchecked(lastChar, lastChar); - _appendToPat(patBuf, lastChar, false); - } - // Treat final trailing '-' as a literal - if (op == '-') { - add_unchecked(op, op); - patBuf.append(op); - } else if (op == '&') { - syntaxError(chars, "Trailing '&'"); - } - patBuf.append(']'); - mode = 2; - continue; - case '-': - if (op == 0) { - if (lastItem != 0) { - op = (char) c; - continue; - } else { - // Treat final trailing '-' as a literal - add_unchecked(c, c); - c = chars.next(opts); - literal = chars.isEscaped(); - if (c == ']' && !literal) { - patBuf.append("-]"); - mode = 2; - continue; - } - } - } - syntaxError(chars, "'-' not after char or set"); - break; - case '&': - if (lastItem == 2 && op == 0) { - op = (char) c; - continue; - } - syntaxError(chars, "'&' not after set"); - break; - case '^': - syntaxError(chars, "'^' not after '['"); - break; - case '{': - if (op != 0) { - syntaxError(chars, "Missing operand after operator"); - } - if (lastItem == 1) { - add_unchecked(lastChar, lastChar); - _appendToPat(patBuf, lastChar, false); - } - lastItem = 0; - if (buf == null) { - buf = new StringBuffer(); - } else { - buf.setLength(0); - } - boolean ok = false; - while (!chars.atEnd()) { - c = chars.next(opts); - literal = chars.isEscaped(); - if (c == '}' && !literal) { - ok = true; - break; - } - UTF16.append(buf, c); - } - if (buf.length() < 1 || !ok) { - syntaxError(chars, "Invalid multicharacter string"); - } - // We have new string. Add it to set and continue; - // we don't need to drop through to the further - // processing - add(buf.toString()); - patBuf.append('{'); - _appendToPat(patBuf, buf.toString(), false); - patBuf.append('}'); - continue; - case SymbolTable.SYMBOL_REF: - // symbols nosymbols - // [a-$] error error (ambiguous) - // [a$] anchor anchor - // [a-$x] var "x"* literal '$' - // [a-$.] error literal '$' - // *We won't get here in the case of var "x" - backup = chars.getPos(backup); - c = chars.next(opts); - literal = chars.isEscaped(); - boolean anchor = (c == ']' && !literal); - if (symbols == null && !anchor) { - c = SymbolTable.SYMBOL_REF; - chars.setPos(backup); - break; // literal '$' - } - if (anchor && op == 0) { - if (lastItem == 1) { - add_unchecked(lastChar, lastChar); - _appendToPat(patBuf, lastChar, false); - } - add_unchecked(UnicodeMatcher.ETHER); - usePat = true; - patBuf.append(SymbolTable.SYMBOL_REF).append(']'); - mode = 2; - continue; - } - syntaxError(chars, "Unquoted '$'"); - break; - default: - break; - } - } - - // -------- Parse literal characters. This includes both - // escaped chars ("\u4E01") and non-syntax characters - // ("a"). - - switch (lastItem) { - case 0: - lastItem = 1; - lastChar = c; - break; - case 1: - if (op == '-') { - if (lastChar >= c) { - // Don't allow redundant (a-a) or empty (b-a) ranges; - // these are most likely typos. - syntaxError(chars, "Invalid range"); - } - add_unchecked(lastChar, c); - _appendToPat(patBuf, lastChar, false); - patBuf.append(op); - _appendToPat(patBuf, c, false); - lastItem = op = 0; - } else { - add_unchecked(lastChar, lastChar); - _appendToPat(patBuf, lastChar, false); - lastChar = c; - } - break; - case 2: - if (op != 0) { - syntaxError(chars, "Set expected after operator"); - } - lastChar = c; - lastItem = 1; - break; - } - } - - if (mode != 2) { - syntaxError(chars, "Missing ']'"); - } - - chars.skipIgnored(opts); - - if (invert) { - complement(); - } - - // Use the rebuilt pattern (pat) only if necessary. Prefer the - // generated pattern. - if (usePat) { - rebuiltPat.append(patBuf.toString()); + private UnicodeSet applyPattern(String pattern, + ParsePosition pos) { + if ("[:age=3.2:]".equals(pattern)) { + checkFrozen(); + VersionInfo version = VersionInfo.getInstance("3.2"); + applyFilter(new VersionFilter(version), UCharacterProperty.SRC_PROPSVEC); } else { - _generatePattern(rebuiltPat, false, true); + throw new IllegalStateException("UnicodeSet.applyPattern(unexpected pattern " + + pattern + ")"); } - } - private static void syntaxError(RuleCharacterIterator chars, String msg) { - throw new IllegalArgumentException("Error: " + msg + " at \"" + - Utility.escape(chars.toString()) + - '"'); + return this; } //---------------------------------------------------------------- @@ -1397,7 +837,6 @@ public class UnicodeSet implements UnicodeMatcher { int[] temp = list; list = buffer; buffer = temp; - pat = null; return this; } @@ -1414,88 +853,87 @@ public class UnicodeSet implements UnicodeMatcher { // change from xor is that we have to check overlapping pairs // polarity bit 1 means a is second, bit 2 means b is. main: - while (true) { - switch (polarity) { - case 0: // both first; take lower if unequal - if (a < b) { // take a - // Back up over overlapping ranges in buffer[] - if (k > 0 && a <= buffer[k-1]) { - // Pick latter end value in buffer[] vs. list[] - a = max(list[i], buffer[--k]); - } else { - // No overlap - buffer[k++] = a; - a = list[i]; + while (true) { + switch (polarity) { + case 0: // both first; take lower if unequal + if (a < b) { // take a + // Back up over overlapping ranges in buffer[] + if (k > 0 && a <= buffer[k-1]) { + // Pick latter end value in buffer[] vs. list[] + a = max(list[i], buffer[--k]); + } else { + // No overlap + buffer[k++] = a; + a = list[i]; + } + i++; // Common if/else code factored out + polarity ^= 1; + } else if (b < a) { // take b + if (k > 0 && b <= buffer[k-1]) { + b = max(other[j], buffer[--k]); + } else { + buffer[k++] = b; + b = other[j]; + } + j++; + polarity ^= 2; + } else { // a == b, take a, drop b + if (a == HIGH) break main; + // This is symmetrical; it doesn't matter if + // we backtrack with a or b. - liu + if (k > 0 && a <= buffer[k-1]) { + a = max(list[i], buffer[--k]); + } else { + // No overlap + buffer[k++] = a; + a = list[i]; + } + i++; + polarity ^= 1; + b = other[j++]; polarity ^= 2; } - i++; // Common if/else code factored out - polarity ^= 1; - } else if (b < a) { // take b - if (k > 0 && b <= buffer[k-1]) { - b = max(other[j], buffer[--k]); - } else { + break; + case 3: // both second; take higher if unequal, and drop other + if (b <= a) { // take a + if (a == HIGH) break main; + buffer[k++] = a; + } else { // take b + if (b == HIGH) break main; buffer[k++] = b; - b = other[j]; } - j++; - polarity ^= 2; - } else { // a == b, take a, drop b - if (a == HIGH) break main; - // This is symmetrical; it doesn't matter if - // we backtrack with a or b. - liu - if (k > 0 && a <= buffer[k-1]) { - a = max(list[i], buffer[--k]); - } else { - // No overlap - buffer[k++] = a; - a = list[i]; + a = list[i++]; polarity ^= 1; // factored common code + b = other[j++]; polarity ^= 2; + break; + case 1: // a second, b first; if b < a, overlap + if (a < b) { // no overlap, take a + buffer[k++] = a; a = list[i++]; polarity ^= 1; + } else if (b < a) { // OVERLAP, drop b + b = other[j++]; polarity ^= 2; + } else { // a == b, drop both! + if (a == HIGH) break main; + a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; } - i++; - polarity ^= 1; - b = other[j++]; polarity ^= 2; + break; + case 2: // a first, b second; if a < b, overlap + if (b < a) { // no overlap, take b + buffer[k++] = b; b = other[j++]; polarity ^= 2; + } else if (a < b) { // OVERLAP, drop a + a = list[i++]; polarity ^= 1; + } else { // a == b, drop both! + if (a == HIGH) break main; + a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; } - break; - case 3: // both second; take higher if unequal, and drop other - if (b <= a) { // take a - if (a == HIGH) break main; - buffer[k++] = a; - } else { // take b - if (b == HIGH) break main; - buffer[k++] = b; - } - a = list[i++]; polarity ^= 1; // factored common code - b = other[j++]; polarity ^= 2; - break; - case 1: // a second, b first; if b < a, overlap - if (a < b) { // no overlap, take a - buffer[k++] = a; a = list[i++]; polarity ^= 1; - } else if (b < a) { // OVERLAP, drop b - b = other[j++]; polarity ^= 2; - } else { // a == b, drop both! - if (a == HIGH) break main; - a = list[i++]; polarity ^= 1; - b = other[j++]; polarity ^= 2; - } - break; - case 2: // a first, b second; if a < b, overlap - if (b < a) { // no overlap, take b - buffer[k++] = b; b = other[j++]; polarity ^= 2; - } else if (a < b) { // OVERLAP, drop a - a = list[i++]; polarity ^= 1; - } else { // a == b, drop both! - if (a == HIGH) break main; - a = list[i++]; polarity ^= 1; - b = other[j++]; polarity ^= 2; - } - break; } - } buffer[k++] = HIGH; // terminate len = k; // swap list and buffer int[] temp = list; list = buffer; buffer = temp; - pat = null; return this; } @@ -1512,61 +950,60 @@ public class UnicodeSet implements UnicodeMatcher { // change from xor is that we have to check overlapping pairs // polarity bit 1 means a is second, bit 2 means b is. main: - while (true) { - switch (polarity) { - case 0: // both first; drop the smaller - if (a < b) { // drop a - a = list[i++]; polarity ^= 1; - } else if (b < a) { // drop b - b = other[j++]; polarity ^= 2; - } else { // a == b, take one, drop other - if (a == HIGH) break main; - buffer[k++] = a; a = list[i++]; polarity ^= 1; - b = other[j++]; polarity ^= 2; + while (true) { + switch (polarity) { + case 0: // both first; drop the smaller + if (a < b) { // drop a + a = list[i++]; polarity ^= 1; + } else if (b < a) { // drop b + b = other[j++]; polarity ^= 2; + } else { // a == b, take one, drop other + if (a == HIGH) break main; + buffer[k++] = a; a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; + case 3: // both second; take lower if unequal + if (a < b) { // take a + buffer[k++] = a; a = list[i++]; polarity ^= 1; + } else if (b < a) { // take b + buffer[k++] = b; b = other[j++]; polarity ^= 2; + } else { // a == b, take one, drop other + if (a == HIGH) break main; + buffer[k++] = a; a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; + case 1: // a second, b first; + if (a < b) { // NO OVERLAP, drop a + a = list[i++]; polarity ^= 1; + } else if (b < a) { // OVERLAP, take b + buffer[k++] = b; b = other[j++]; polarity ^= 2; + } else { // a == b, drop both! + if (a == HIGH) break main; + a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; + case 2: // a first, b second; if a < b, overlap + if (b < a) { // no overlap, drop b + b = other[j++]; polarity ^= 2; + } else if (a < b) { // OVERLAP, take a + buffer[k++] = a; a = list[i++]; polarity ^= 1; + } else { // a == b, drop both! + if (a == HIGH) break main; + a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; } - break; - case 3: // both second; take lower if unequal - if (a < b) { // take a - buffer[k++] = a; a = list[i++]; polarity ^= 1; - } else if (b < a) { // take b - buffer[k++] = b; b = other[j++]; polarity ^= 2; - } else { // a == b, take one, drop other - if (a == HIGH) break main; - buffer[k++] = a; a = list[i++]; polarity ^= 1; - b = other[j++]; polarity ^= 2; - } - break; - case 1: // a second, b first; - if (a < b) { // NO OVERLAP, drop a - a = list[i++]; polarity ^= 1; - } else if (b < a) { // OVERLAP, take b - buffer[k++] = b; b = other[j++]; polarity ^= 2; - } else { // a == b, drop both! - if (a == HIGH) break main; - a = list[i++]; polarity ^= 1; - b = other[j++]; polarity ^= 2; - } - break; - case 2: // a first, b second; if a < b, overlap - if (b < a) { // no overlap, drop b - b = other[j++]; polarity ^= 2; - } else if (a < b) { // OVERLAP, take a - buffer[k++] = a; a = list[i++]; polarity ^= 1; - } else { // a == b, drop both! - if (a == HIGH) break main; - a = list[i++]; polarity ^= 1; - b = other[j++]; polarity ^= 2; - } - break; } - } buffer[k++] = HIGH; // terminate len = k; // swap list and buffer int[] temp = list; list = buffer; buffer = temp; - pat = null; return this; } @@ -1582,58 +1019,46 @@ public class UnicodeSet implements UnicodeMatcher { boolean contains(int codePoint); } - // VersionInfo for unassigned characters - static final VersionInfo NO_VERSION = VersionInfo.getInstance(0, 0, 0, 0); + private static final VersionInfo NO_VERSION = VersionInfo.getInstance(0, 0, 0, 0); private static class VersionFilter implements Filter { VersionInfo version; - VersionFilter(VersionInfo version) { this.version = version; } - public boolean contains(int ch) { VersionInfo v = UCharacter.getAge(ch); // Reference comparison ok; VersionInfo caches and reuses // unique objects. return v != NO_VERSION && - v.compareTo(version) <= 0; + v.compareTo(version) <= 0; } } private static synchronized UnicodeSet getInclusions(int src) { - if (INCLUSIONS == null) { - INCLUSIONS = new UnicodeSet[UCharacterProperty.SRC_COUNT]; + if (src != UCharacterProperty.SRC_PROPSVEC) { + throw new IllegalStateException("UnicodeSet.getInclusions(unknown src "+src+")"); } - if(INCLUSIONS[src] == null) { + + if (INCLUSION == null) { UnicodeSet incl = new UnicodeSet(); - switch(src) { - case UCharacterProperty.SRC_PROPSVEC: - UCharacterProperty.getInstance().upropsvec_addPropertyStarts(incl); - break; - default: - throw new IllegalStateException("UnicodeSet.getInclusions(unknown src "+src+")"); - } - INCLUSIONS[src] = incl; + UCharacterProperty.INSTANCE.upropsvec_addPropertyStarts(incl); + INCLUSION = incl; } - return INCLUSIONS[src]; + return INCLUSION; } /** * Generic filter-based scanning code for UCD property UnicodeSets. */ private UnicodeSet applyFilter(Filter filter, int src) { - // Walk through all Unicode characters, noting the start + // Logically, walk through all Unicode characters, noting the start // and end of each range for which filter.contain(c) is // true. Add each range to a set. // - // To improve performance, use the INCLUSIONS set, which + // To improve performance, use an inclusions set which // encodes information about character ranges that are known - // to have identical properties, such as the CJK Ideographs - // from U+4E00 to U+9FA5. INCLUSIONS contains all characters - // except the first characters of such ranges. - // - // TODO Where possible, instead of scanning over code points, - // use internal property data to initialize UnicodeSets for - // those properties. Scanning code points is slow. + // to have identical properties. + // getInclusions(src) contains exactly the first characters of + // same-value ranges for the given properties "source". clear(); @@ -1668,204 +1093,315 @@ public class UnicodeSet implements UnicodeMatcher { } /** - * Remove leading and trailing rule white space and compress - * internal rule white space to a single space character. + * Is this frozen, according to the Freezable interface? * - * @see UCharacterProperty#isRuleWhiteSpace + * @return value + * @stable ICU 3.8 */ - private static String mungeCharName(String source) { - StringBuffer buf = new StringBuffer(); - for (int i=0; i<source.length(); ) { - int ch = UTF16.charAt(source, i); - i += UTF16.getCharCount(ch); - if (UCharacterProperty.isRuleWhiteSpace(ch)) { - if (buf.length() == 0 || - buf.charAt(buf.length() - 1) == ' ') { - continue; + public boolean isFrozen() { + return (bmpSet != null || stringSpan != null); + } + + /** + * Freeze this class, according to the Freezable interface. + * + * @return this + * @stable ICU 4.4 + */ + public UnicodeSet freeze() { + if (!isFrozen()) { + // Do most of what compact() does before freezing because + // compact() will not work when the set is frozen. + // Small modification: Don't shrink if the savings would be tiny (<=GROW_EXTRA). + + // Delete buffer first to defragment memory less. + buffer = null; + if (list.length > (len + GROW_EXTRA)) { + // Make the capacity equal to len or 1. + // We don't want to realloc of 0 size. + int capacity = (len == 0) ? 1 : len; + int[] oldList = list; + list = new int[capacity]; + for (int i = capacity; i-- > 0;) { + list[i] = oldList[i]; } - ch = ' '; // convert to ' ' } - UTF16.append(buf, ch); - } - if (buf.length() != 0 && - buf.charAt(buf.length() - 1) == ' ') { - buf.setLength(buf.length() - 1); - } - return buf.toString(); - } - /** - * Modifies this set to contain those code points which have the - * given value for the given property. Prior contents of this - * set are lost. - * @param propertyAlias the property alias - * @param valueAlias the value alias - * @param symbols if not null, then symbols are first called to see if a property - * is available. If true, then everything else is skipped. - * @return this set - * @stable ICU 3.2 - */ - public UnicodeSet applyPropertyAlias(String propertyAlias, - String valueAlias, SymbolTable symbols) { - if (valueAlias.length() > 0) { - if (propertyAlias.equals("Age")) { - // Must munge name, since - // VersionInfo.getInstance() does not do - // 'loose' matching. - VersionInfo version = VersionInfo.getInstance(mungeCharName(valueAlias)); - applyFilter(new VersionFilter(version), UCharacterProperty.SRC_PROPSVEC); - return this; + // Optimize contains() and span() and similar functions. + if (!strings.isEmpty()) { + stringSpan = new UnicodeSetStringSpan(this, new ArrayList<String>(strings), UnicodeSetStringSpan.ALL); + } + if (stringSpan == null || !stringSpan.needsStringSpanUTF16()) { + // Optimize for code point spans. + // There are no strings, or + // all strings are irrelevant for span() etc. because + // all of each string's code points are contained in this set. + // However, fully contained strings are relevant for spanAndCount(), + // so we create both objects. + bmpSet = new BMPSet(list, len); } } - throw new IllegalArgumentException("Unsupported property: " + propertyAlias); - } - - /** - * Return true if the given iterator appears to point at a - * property pattern. Regardless of the result, return with the - * iterator unchanged. - * @param chars iterator over the pattern characters. Upon return - * it will be unchanged. - * @param iterOpts RuleCharacterIterator options - */ - private static boolean resemblesPropertyPattern(RuleCharacterIterator chars, - int iterOpts) { - boolean result = false; - iterOpts &= ~RuleCharacterIterator.PARSE_ESCAPES; - Object pos = chars.getPos(null); - int c = chars.next(iterOpts); - if (c == '[' || c == '\\') { - int d = chars.next(iterOpts & ~RuleCharacterIterator.SKIP_WHITESPACE); - result = (c == '[') ? (d == ':') : - (d == 'N' || d == 'p' || d == 'P'); - } - chars.setPos(pos); - return result; - } - - /** - * Parse the given property pattern at the given parse position. - * @param symbols TODO - */ - private UnicodeSet applyPropertyPattern(String pattern, ParsePosition ppos, SymbolTable symbols) { - int pos = ppos.getIndex(); - - // On entry, ppos should point to one of the following locations: - - // Minimum length is 5 characters, e.g. \p{L} - if ((pos+5) > pattern.length()) { - return null; - } - - boolean posix = false; // true for [:pat:], false for \p{pat} \P{pat} \N{pat} - boolean isName = false; // true for \N{pat}, o/w false - boolean invert = false; - - // Look for an opening [:, [:^, \p, or \P - if (pattern.regionMatches(pos, "[:", 0, 2)) { - posix = true; - pos = Utility.skipWhitespace(pattern, pos+2); - if (pos < pattern.length() && pattern.charAt(pos) == '^') { - ++pos; - invert = true; - } - } else if (pattern.regionMatches(true, pos, "\\p", 0, 2) || - pattern.regionMatches(pos, "\\N", 0, 2)) { - char c = pattern.charAt(pos+1); - invert = (c == 'P'); - isName = (c == 'N'); - pos = Utility.skipWhitespace(pattern, pos+2); - if (pos == pattern.length() || pattern.charAt(pos++) != '{') { - // Syntax error; "\p" or "\P" not followed by "{" - return null; - } - } else { - // Open delimiter not seen - return null; - } - - // Look for the matching close delimiter, either :] or } - int close = pattern.indexOf(posix ? ":]" : "}", pos); - if (close < 0) { - // Syntax error; close delimiter missing - return null; - } - - // Look for an '=' sign. If this is present, we will parse a - // medium \p{gc=Cf} or long \p{GeneralCategory=Format} - // pattern. - int equals = pattern.indexOf('=', pos); - String propName, valueName; - if (equals >= 0 && equals < close && !isName) { - // Equals seen; parse medium/long pattern - propName = pattern.substring(pos, equals); - valueName = pattern.substring(equals+1, close); - } - - else { - // Handle case where no '=' is seen, and \N{} - propName = pattern.substring(pos, close); - valueName = ""; - - // Handle \N{name} - if (isName) { - // This is a little inefficient since it means we have to - // parse "na" back to UProperty.NAME even though we already - // know it's UProperty.NAME. If we refactor the API to - // support args of (int, String) then we can remove - // "na" and make this a little more efficient. - valueName = propName; - propName = "na"; - } - } - - applyPropertyAlias(propName, valueName, symbols); - - if (invert) { - complement(); - } - - // Move to the limit position after the close delimiter - ppos.setIndex(close + (posix ? 2 : 1)); - return this; } /** - * Parse a property pattern. - * @param chars iterator over the pattern characters. Upon return - * it will be advanced to the first character after the parsed - * pattern, or the end of the iteration if all characters are - * parsed. - * @param rebuiltPat the pattern that was parsed, rebuilt or - * copied from the input pattern, as appropriate. - * @param symbols TODO + * Span a string using this UnicodeSet. + * <p>To replace, count elements, or delete spans, see {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * @param s The string to be spanned + * @param spanCondition The span condition + * @return the length of the span + * @stable ICU 4.4 */ - private void applyPropertyPattern(RuleCharacterIterator chars, - StringBuffer rebuiltPat, SymbolTable symbols) { - String patStr = chars.lookahead(); - ParsePosition pos = new ParsePosition(0); - applyPropertyPattern(patStr, pos, symbols); - if (pos.getIndex() == 0) { - syntaxError(chars, "Invalid property pattern"); - } - chars.jumpahead(pos.getIndex()); - rebuiltPat.append(patStr, 0, pos.getIndex()); + public int span(CharSequence s, SpanCondition spanCondition) { + return span(s, 0, spanCondition); } - //---------------------------------------------------------------- - // Case folding API - //---------------------------------------------------------------- + /** + * Span a string using this UnicodeSet. + * If the start index is less than 0, span will start from 0. + * If the start index is greater than the string length, span returns the string length. + * <p>To replace, count elements, or delete spans, see {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @return the string index which ends the span (i.e. exclusive) + * @stable ICU 4.4 + */ + public int span(CharSequence s, int start, SpanCondition spanCondition) { + int end = s.length(); + if (start < 0) { + start = 0; + } else if (start >= end) { + return end; + } + if (bmpSet != null) { + // Frozen set without strings, or no string is relevant for span(). + return bmpSet.span(s, start, spanCondition, null); + } + if (stringSpan != null) { + return stringSpan.span(s, start, spanCondition); + } else if (!strings.isEmpty()) { + int which = spanCondition == SpanCondition.NOT_CONTAINED ? UnicodeSetStringSpan.FWD_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.FWD_UTF16_CONTAINED; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList<String>(strings), which); + if (strSpan.needsStringSpanUTF16()) { + return strSpan.span(s, start, spanCondition); + } + } + + return spanCodePointsAndCount(s, start, spanCondition, null); + } /** - * Bitmask for constructor and applyPattern() indicating that - * white space should be ignored. If set, ignore characters for - * which UCharacterProperty.isRuleWhiteSpace() returns true, - * unless they are quoted or escaped. This may be ORed together - * with other selectors. - * @stable ICU 3.8 + * Same as span() but also counts the smallest number of set elements on any path across the span. + * <p>To replace, count elements, or delete spans, see {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * @param outCount An output-only object (must not be null) for returning the count. + * @return the limit (exclusive end) of the span */ - public static final int IGNORE_SPACE = 1; + public int spanAndCount(CharSequence s, int start, SpanCondition spanCondition, OutputInt outCount) { + if (outCount == null) { + throw new IllegalArgumentException("outCount must not be null"); + } + int end = s.length(); + if (start < 0) { + start = 0; + } else if (start >= end) { + return end; + } + if (stringSpan != null) { + // We might also have bmpSet != null, + // but fully-contained strings are relevant for counting elements. + return stringSpan.spanAndCount(s, start, spanCondition, outCount); + } else if (bmpSet != null) { + return bmpSet.span(s, start, spanCondition, outCount); + } else if (!strings.isEmpty()) { + int which = spanCondition == SpanCondition.NOT_CONTAINED ? UnicodeSetStringSpan.FWD_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.FWD_UTF16_CONTAINED; + which |= UnicodeSetStringSpan.WITH_COUNT; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList<String>(strings), which); + return strSpan.spanAndCount(s, start, spanCondition, outCount); + } + + return spanCodePointsAndCount(s, start, spanCondition, outCount); + } + + private int spanCodePointsAndCount(CharSequence s, int start, + SpanCondition spanCondition, OutputInt outCount) { + // Pin to 0/1 values. + boolean spanContained = (spanCondition != SpanCondition.NOT_CONTAINED); + + int c; + int next = start; + int length = s.length(); + int count = 0; + do { + c = Character.codePointAt(s, next); + if (spanContained != contains(c)) { + break; + } + ++count; + next += Character.charCount(c); + } while (next < length); + if (outCount != null) { outCount.value = count; } + return next; + } + + /** + * Span a string backwards (from the fromIndex) using this UnicodeSet. + * If the fromIndex is less than 0, spanBack will return 0. + * If fromIndex is greater than the string length, spanBack will start from the string length. + * <p>To replace, count elements, or delete spans, see {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * @param s The string to be spanned + * @param fromIndex The index of the char (exclusive) that the string should be spanned backwards + * @param spanCondition The span condition + * @return The string index which starts the span (i.e. inclusive). + * @stable ICU 4.4 + */ + public int spanBack(CharSequence s, int fromIndex, SpanCondition spanCondition) { + if (fromIndex <= 0) { + return 0; + } + if (fromIndex > s.length()) { + fromIndex = s.length(); + } + if (bmpSet != null) { + // Frozen set without strings, or no string is relevant for spanBack(). + return bmpSet.spanBack(s, fromIndex, spanCondition); + } + if (stringSpan != null) { + return stringSpan.spanBack(s, fromIndex, spanCondition); + } else if (!strings.isEmpty()) { + int which = (spanCondition == SpanCondition.NOT_CONTAINED) + ? UnicodeSetStringSpan.BACK_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.BACK_UTF16_CONTAINED; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList<String>(strings), which); + if (strSpan.needsStringSpanUTF16()) { + return strSpan.spanBack(s, fromIndex, spanCondition); + } + } + + // Pin to 0/1 values. + boolean spanContained = (spanCondition != SpanCondition.NOT_CONTAINED); + + int c; + int prev = fromIndex; + do { + c = Character.codePointBefore(s, prev); + if (spanContained != contains(c)) { + break; + } + prev -= Character.charCount(c); + } while (prev > 0); + return prev; + } + + /** + * Clone a thawed version of this class, according to the Freezable interface. + * @return the clone, not frozen + * @stable ICU 4.4 + */ + public UnicodeSet cloneAsThawed() { + UnicodeSet result = new UnicodeSet(this); + assert !result.isFrozen(); + return result; + } + + // internal function + private void checkFrozen() { + if (isFrozen()) { + throw new UnsupportedOperationException("Attempt to modify frozen object"); + } + } + + /** + * Argument values for whether span() and similar functions continue while the current character is contained vs. + * not contained in the set. + * <p> + * The functionality is straightforward for sets with only single code points, without strings (which is the common + * case): + * <ul> + * <li>CONTAINED and SIMPLE work the same. + * <li>CONTAINED and SIMPLE are inverses of NOT_CONTAINED. + * <li>span() and spanBack() partition any string the + * same way when alternating between span(NOT_CONTAINED) and span(either "contained" condition). + * <li>Using a + * complemented (inverted) set and the opposite span conditions yields the same results. + * </ul> + * When a set contains multi-code point strings, then these statements may not be true, depending on the strings in + * the set (for example, whether they overlap with each other) and the string that is processed. For a set with + * strings: + * <ul> + * <li>The complement of the set contains the opposite set of code points, but the same set of strings. + * Therefore, complementing both the set and the span conditions may yield different results. + * <li>When starting spans + * at different positions in a string (span(s, ...) vs. span(s+1, ...)) the ends of the spans may be different + * because a set string may start before the later position. + * <li>span(SIMPLE) may be shorter than + * span(CONTAINED) because it will not recursively try all possible paths. For example, with a set which + * contains the three strings "xy", "xya" and "ax", span("xyax", CONTAINED) will return 4 but span("xyax", + * SIMPLE) will return 3. span(SIMPLE) will never be longer than span(CONTAINED). + * <li>With either "contained" condition, span() and spanBack() may partition a string in different ways. For example, + * with a set which contains the two strings "ab" and "ba", and when processing the string "aba", span() will yield + * contained/not-contained boundaries of { 0, 2, 3 } while spanBack() will yield boundaries of { 0, 1, 3 }. + * </ul> + * Note: If it is important to get the same boundaries whether iterating forward or backward through a string, then + * either only span() should be used and the boundaries cached for backward operation, or an ICU BreakIterator could + * be used. + * <p> + * Note: Unpaired surrogates are treated like surrogate code points. Similarly, set strings match only on code point + * boundaries, never in the middle of a surrogate pair. + * + * @stable ICU 4.4 + */ + public enum SpanCondition { + /** + * Continues a span() while there is no set element at the current position. + * Increments by one code point at a time. + * Stops before the first set element (character or string). + * (For code points only, this is like while contains(current)==false). + * <p> + * When span() returns, the substring between where it started and the position it returned consists only of + * characters that are not in the set, and none of its strings overlap with the span. + * + * @stable ICU 4.4 + */ + NOT_CONTAINED, + + /** + * Spans the longest substring that is a concatenation of set elements (characters or strings). + * (For characters only, this is like while contains(current)==true). + * <p> + * When span() returns, the substring between where it started and the position it returned consists only of set + * elements (characters or strings) that are in the set. + * <p> + * If a set contains strings, then the span will be the longest substring for which there + * exists at least one non-overlapping concatenation of set elements (characters or strings). + * This is equivalent to a POSIX regular expression for <code>(OR of each set element)*</code>. + * (Java/ICU/Perl regex stops at the first match of an OR.) + * + * @stable ICU 4.4 + */ + CONTAINED, + + /** + * Continues a span() while there is a set element at the current position. + * Increments by the longest matching element at each position. + * (For characters only, this is like while contains(current)==true). + * <p> + * When span() returns, the substring between where it started and the position it returned consists only of set + * elements (characters or strings) that are in the set. + * <p> + * If a set only contains single characters, then this is the same as CONTAINED. + * <p> + * If a set contains strings, then the span will be the longest substring with a match at each position with the + * longest single set element (character or string). + * <p> + * Use this span condition together with other longest-match algorithms, such as ICU converters + * (ucnv_getUnicodeSet()). + * + * @stable ICU 4.4 + */ + SIMPLE, + } } - diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSetIterator.java b/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSetIterator.java deleted file mode 100644 index 98544705349..00000000000 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSetIterator.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. - * 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. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * - ******************************************************************************* - */ - -package sun.text.normalizer; - -import java.util.Iterator; - -/** - * UnicodeSetIterator iterates over the contents of a UnicodeSet. It - * iterates over either code points or code point ranges. After all - * code points or ranges have been returned, it returns the - * multicharacter strings of the UnicodSet, if any. - * - * <p>To iterate over code points, use a loop like this: - * <pre> - * UnicodeSetIterator it(set); - * while (set.next()) { - * if (set.codepoint != UnicodeSetIterator::IS_STRING) { - * processCodepoint(set.codepoint); - * } else { - * processString(set.string); - * } - * } - * </pre> - * - * <p>To iterate over code point ranges, use a loop like this: - * <pre> - * UnicodeSetIterator it(set); - * while (set.nextRange()) { - * if (set.codepoint != UnicodeSetIterator::IS_STRING) { - * processCodepointRange(set.codepoint, set.codepointEnd); - * } else { - * processString(set.string); - * } - * } - * </pre> - * @author M. Davis - * @stable ICU 2.0 - */ -public class UnicodeSetIterator { - - /** - * Value of {@code codepoint} if the iterator points to a string. - * If {@code codepoint == IS_STRING}, then examine - * {@code string} for the current iteration result. - * @stable ICU 2.0 - */ - public static int IS_STRING = -1; - - /** - * Current code point, or the special value {@code IS_STRING}, if - * the iterator points to a string. - * @stable ICU 2.0 - */ - public int codepoint; - - /** - * When iterating over ranges using {@code nextRange()}, - * {@code codepointEnd} contains the inclusive end of the - * iteration range, if {@code codepoint != IS_STRING}. If - * iterating over code points using {@code next()}, or if - * {@code codepoint == IS_STRING}, then the value of - * {@code codepointEnd} is undefined. - * @stable ICU 2.0 - */ - public int codepointEnd; - - /** - * If {@code codepoint == IS_STRING}, then {@code string} points - * to the current string. If {@code codepoint != IS_STRING}, the - * value of {@code string} is undefined. - * @stable ICU 2.0 - */ - public String string; - - /** - * Create an iterator over the given set. - * @param set set to iterate over - * @stable ICU 2.0 - */ - public UnicodeSetIterator(UnicodeSet set) { - reset(set); - } - - /** - * Returns the next element in the set, either a code point range - * or a string. If there are no more elements in the set, return - * false. If {@code codepoint == IS_STRING}, the value is a - * string in the {@code string} field. Otherwise the value is a - * range of one or more code points from {@code codepoint} to - * {@code codepointeEnd} inclusive. - * - * <p>The order of iteration is all code points ranges in sorted - * order, followed by all strings sorted order. Ranges are - * disjoint and non-contiguous. {@code string} is undefined - * unless {@code codepoint == IS_STRING}. Do not mix calls to - * {@code next()} and {@code nextRange()} without calling - * {@code reset()} between them. The results of doing so are - * undefined. - * - * @return true if there was another element in the set and this - * object contains the element. - * @stable ICU 2.0 - */ - public boolean nextRange() { - if (nextElement <= endElement) { - codepointEnd = endElement; - codepoint = nextElement; - nextElement = endElement+1; - return true; - } - if (range < endRange) { - loadRange(++range); - codepointEnd = endElement; - codepoint = nextElement; - nextElement = endElement+1; - return true; - } - - // stringIterator == null iff there are no string elements remaining - - if (stringIterator == null) return false; - codepoint = IS_STRING; // signal that value is actually a string - string = stringIterator.next(); - if (!stringIterator.hasNext()) stringIterator = null; - return true; - } - - /** - * Sets this iterator to visit the elements of the given set and - * resets it to the start of that set. The iterator is valid only - * so long as {@code set} is valid. - * @param uset the set to iterate over. - * @stable ICU 2.0 - */ - public void reset(UnicodeSet uset) { - set = uset; - reset(); - } - - /** - * Resets this iterator to the start of the set. - * @stable ICU 2.0 - */ - public void reset() { - endRange = set.getRangeCount() - 1; - range = 0; - endElement = -1; - nextElement = 0; - if (endRange >= 0) { - loadRange(range); - } - stringIterator = null; - if (set.strings != null) { - stringIterator = set.strings.iterator(); - if (!stringIterator.hasNext()) stringIterator = null; - } - } - - // ======================= PRIVATES =========================== - - private UnicodeSet set; - private int endRange = 0; - private int range = 0; - /** - * @internal - */ - protected int endElement; - /** - * @internal - */ - protected int nextElement; - private Iterator<String> stringIterator = null; - - /** - * Invariant: stringIterator is null when there are no (more) strings remaining - */ - - /** - * @internal - */ - protected void loadRange(int aRange) { - nextElement = set.getRangeStart(aRange); - endElement = set.getRangeEnd(aRange); - } -} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSetStringSpan.java b/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSetStringSpan.java new file mode 100644 index 00000000000..4ba07db11c6 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSetStringSpan.java @@ -0,0 +1,1165 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* + ****************************************************************************** + * + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + * + ****************************************************************************** + */ + +package sun.text.normalizer; + +import java.util.ArrayList; + +import sun.text.normalizer.UnicodeSet.SpanCondition; + +/* + * Implement span() etc. for a set with strings. + * Avoid recursion because of its exponential complexity. + * Instead, try multiple paths at once and track them with an IndexList. + */ +class UnicodeSetStringSpan { + + /* + * Which span() variant will be used? The object is either built for one variant and used once, + * or built for all and may be used many times. + */ + public static final int WITH_COUNT = 0x40; // spanAndCount() may be called + public static final int FWD = 0x20; + public static final int BACK = 0x10; + // public static final int UTF16 = 8; + public static final int CONTAINED = 2; + public static final int NOT_CONTAINED = 1; + + public static final int ALL = 0x7f; + + public static final int FWD_UTF16_CONTAINED = FWD | /* UTF16 | */ CONTAINED; + public static final int FWD_UTF16_NOT_CONTAINED = FWD | /* UTF16 | */NOT_CONTAINED; + public static final int BACK_UTF16_CONTAINED = BACK | /* UTF16 | */ CONTAINED; + public static final int BACK_UTF16_NOT_CONTAINED = BACK | /* UTF16 | */NOT_CONTAINED; + + /** + * Special spanLength short values. (since Java has not unsigned byte type) + * All code points in the string are contained in the parent set. + */ + static final short ALL_CP_CONTAINED = 0xff; + + /** The spanLength is >=0xfe. */ + static final short LONG_SPAN = ALL_CP_CONTAINED - 1; + + /** Set for span(). Same as parent but without strings. */ + private UnicodeSet spanSet; + + /** + * Set for span(not contained). + * Same as spanSet, plus characters that start or end strings. + */ + private UnicodeSet spanNotSet; + + /** The strings of the parent set. */ + private ArrayList<String> strings; + + /** The lengths of span(), spanBack() etc. for each string. */ + private short[] spanLengths; + + /** Maximum lengths of relevant strings. */ + private int maxLength16; + + /** Are there strings that are not fully contained in the code point set? */ + private boolean someRelevant; + + /** Set up for all variants of span()? */ + private boolean all; + + /** Span helper */ + private OffsetList offsets; + + /** + * Constructs for all variants of span(), or only for any one variant. + * Initializes as little as possible, for single use. + */ + public UnicodeSetStringSpan(final UnicodeSet set, final ArrayList<String> setStrings, int which) { + spanSet = new UnicodeSet(0, 0x10ffff); + // TODO: With Java 6, just take the parent set's strings as is, + // as a NavigableSet<String>, rather than as an ArrayList copy of the set of strings. + // Then iterate via the first() and higher() methods. + // (We do not want to create multiple Iterator objects in each span().) + // See ICU ticket #7454. + strings = setStrings; + all = (which == ALL); + spanSet.retainAll(set); + if (0 != (which & NOT_CONTAINED)) { + // Default to the same sets. + // addToSpanNotSet() will create a separate set if necessary. + spanNotSet = spanSet; + } + offsets = new OffsetList(); + + // Determine if the strings even need to be taken into account at all for span() etc. + // If any string is relevant, then all strings need to be used for + // span(longest match) but only the relevant ones for span(while contained). + // TODO: Possible optimization: Distinguish CONTAINED vs. LONGEST_MATCH + // and do not store UTF-8 strings if !thisRelevant and CONTAINED. + // (Only store irrelevant UTF-8 strings for LONGEST_MATCH where they are relevant after all.) + // Also count the lengths of the UTF-8 versions of the strings for memory allocation. + int stringsLength = strings.size(); + + int i, spanLength; + someRelevant = false; + for (i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + spanLength = spanSet.span(string, SpanCondition.CONTAINED); + if (spanLength < length16) { // Relevant string. + someRelevant = true; + } + if (/* (0 != (which & UTF16)) && */ length16 > maxLength16) { + maxLength16 = length16; + } + } + if (!someRelevant && (which & WITH_COUNT) == 0) { + return; + } + + // Freeze after checking for the need to use strings at all because freezing + // a set takes some time and memory which are wasted if there are no relevant strings. + if (all) { + spanSet.freeze(); + } + + int spanBackLengthsOffset; + + // Allocate a block of meta data. + int allocSize; + if (all) { + // 2 sets of span lengths + allocSize = stringsLength * (2); + } else { + allocSize = stringsLength; // One set of span lengths. + } + spanLengths = new short[allocSize]; + + if (all) { + // Store span lengths for all span() variants. + spanBackLengthsOffset = stringsLength; + } else { + // Store span lengths for only one span() variant. + spanBackLengthsOffset = 0; + } + + // Set the meta data and spanNotSet and write the UTF-8 strings. + + for (i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + spanLength = spanSet.span(string, SpanCondition.CONTAINED); + if (spanLength < length16) { // Relevant string. + if (true /* 0 != (which & UTF16) */) { + if (0 != (which & CONTAINED)) { + if (0 != (which & FWD)) { + spanLengths[i] = makeSpanLengthByte(spanLength); + } + if (0 != (which & BACK)) { + spanLength = length16 + - spanSet.spanBack(string, length16, SpanCondition.CONTAINED); + spanLengths[spanBackLengthsOffset + i] = makeSpanLengthByte(spanLength); + } + } else /* not CONTAINED, not all, but NOT_CONTAINED */{ + spanLengths[i] = spanLengths[spanBackLengthsOffset + i] = 0; // Only store a relevant/irrelevant + // flag. + } + } + if (0 != (which & NOT_CONTAINED)) { + // Add string start and end code points to the spanNotSet so that + // a span(while not contained) stops before any string. + int c; + if (0 != (which & FWD)) { + c = string.codePointAt(0); + addToSpanNotSet(c); + } + if (0 != (which & BACK)) { + c = string.codePointBefore(length16); + addToSpanNotSet(c); + } + } + } else { // Irrelevant string. + if (all) { + spanLengths[i] = spanLengths[spanBackLengthsOffset + i] = ALL_CP_CONTAINED; + } else { + // All spanXYZLengths pointers contain the same address. + spanLengths[i] = ALL_CP_CONTAINED; + } + } + } + + // Finish. + if (all) { + spanNotSet.freeze(); + } + } + + /** + * Do the strings need to be checked in span() etc.? + * + * @return true if strings need to be checked (call span() here), + * false if not (use a BMPSet for best performance). + */ + public boolean needsStringSpanUTF16() { + return someRelevant; + } + + /** For fast UnicodeSet::contains(c). */ + public boolean contains(int c) { + return spanSet.contains(c); + } + + /** + * Adds a starting or ending string character to the spanNotSet + * so that a character span ends before any string. + */ + private void addToSpanNotSet(int c) { + if (spanNotSet == null || spanNotSet == spanSet) { + if (spanSet.contains(c)) { + return; // Nothing to do. + } + spanNotSet = spanSet.cloneAsThawed(); + } + spanNotSet.add(c); + } + + /* + * Note: In span() when spanLength==0 + * (after a string match, or at the beginning after an empty code point span) + * and in spanNot() and spanNotUTF8(), + * string matching could use a binary search because all string matches are done + * from the same start index. + * + * For UTF-8, this would require a comparison function that returns UTF-16 order. + * + * This optimization should not be necessary for normal UnicodeSets because most sets have no strings, and most sets + * with strings have very few very short strings. For cases with many strings, it might be better to use a different + * API and implementation with a DFA (state machine). + */ + + /* + * Algorithm for span(SpanCondition.CONTAINED) + * + * Theoretical algorithm: + * - Iterate through the string, and at each code point boundary: + * + If the code point there is in the set, then remember to continue after it. + * + If a set string matches at the current position, then remember to continue after it. + * + Either recursively span for each code point or string match, or recursively span + * for all but the shortest one and iteratively continue the span with the shortest local match. + * + Remember the longest recursive span (the farthest end point). + * + If there is no match at the current position, + * neither for the code point there nor for any set string, + * then stop and return the longest recursive span length. + * + * Optimized implementation: + * + * (We assume that most sets will have very few very short strings. + * A span using a string-less set is extremely fast.) + * + * Create and cache a spanSet which contains all of the single code points of the original set + * but none of its strings. + * + * - Start with spanLength=spanSet.span(SpanCondition.CONTAINED). + * - Loop: + * + Try to match each set string at the end of the spanLength. + * ~ Set strings that start with set-contained code points + * must be matched with a partial overlap + * because the recursive algorithm would have tried to match them at every position. + * ~ Set strings that entirely consist of set-contained code points + * are irrelevant for span(SpanCondition.CONTAINED) + * because the recursive algorithm would continue after them anyway and + * find the longest recursive match from their end. + * ~ Rather than recursing, note each end point of a set string match. + * + If no set string matched after spanSet.span(), + * then return with where the spanSet.span() ended. + * + If at least one set string matched after spanSet.span(), + * then pop the shortest string match end point and continue the loop, + * trying to match all set strings from there. + * + If at least one more set string matched after a previous string match, then test if the + * code point after the previous string match is also contained in the set. + * Continue the loop with the shortest end point of + * either this code point or a matching set string. + * + If no more set string matched after a previous string match, + * then try another spanLength=spanSet.span(SpanCondition.CONTAINED). + * Stop if spanLength==0, otherwise continue the loop. + * + * By noting each end point of a set string match, the function visits each string position at most once and + * finishes in linear time. + * + * The recursive algorithm may visit the same string position many times + * if multiple paths lead to it and finishes in exponential time. + */ + + /* + * Algorithm for span(SIMPLE) + * + * Theoretical algorithm: + * - Iterate through the string, and at each code point boundary: + * + If the code point there is in the set, then remember to continue after it. + * + If a set string matches at the current position, then remember to continue after it. + * + Continue from the farthest match position and ignore all others. + * + If there is no match at the current position, then stop and return the current position. + * + * Optimized implementation: + * + * (Same assumption and spanSet as above.) + * + * - Start with spanLength=spanSet.span(SpanCondition.CONTAINED). + * - Loop: + * + Try to match each set string at the end of the spanLength. + * ~ Set strings that start with set-contained code points + * must be matched with a partial overlap + * because the standard algorithm would have tried to match them earlier. + * ~ Set strings that entirely consist of set-contained code points + * must be matched with a full overlap because the longest-match algorithm + * would hide set string matches that end earlier. + * Such set strings need not be matched earlier inside the code point span + * because the standard algorithm would then have + * continued after the set string match anyway. + * ~ Remember the longest set string match (farthest end point) + * from the earliest starting point. + * + If no set string matched after spanSet.span(), + * then return with where the spanSet.span() ended. + * + If at least one set string matched, + * then continue the loop after the longest match from the earliest position. + * + If no more set string matched after a previous string match, + * then try another spanLength=spanSet.span(SpanCondition.CONTAINED). + * Stop if spanLength==0, otherwise continue the loop. + */ + /** + * Spans a string. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @return the limit (exclusive end) of the span + */ + public int span(CharSequence s, int start, SpanCondition spanCondition) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNot(s, start, null); + } + int spanLimit = spanSet.span(s, start, SpanCondition.CONTAINED); + if (spanLimit == s.length()) { + return spanLimit; + } + return spanWithStrings(s, start, spanLimit, spanCondition); + } + + /** + * Synchronized method for complicated spans using the offsets. + * Avoids synchronization for simple cases. + * + * @param spanLimit = spanSet.span(s, start, CONTAINED) + */ + private synchronized int spanWithStrings(CharSequence s, int start, int spanLimit, + SpanCondition spanCondition) { + // Consider strings; they may overlap with the span. + int initSize = 0; + if (spanCondition == SpanCondition.CONTAINED) { + // Use offset list to try all possibilities. + initSize = maxLength16; + } + offsets.setMaxLength(initSize); + int length = s.length(); + int pos = spanLimit, rest = length - spanLimit; + int spanLength = spanLimit - start; + int i, stringsLength = strings.size(); + for (;;) { + if (spanCondition == SpanCondition.CONTAINED) { + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[i]; + if (overlap == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-overlap..pos. + if (overlap >= LONG_SPAN) { + overlap = length16; + // While contained: No point matching fully inside the code point span. + overlap = string.offsetByCodePoints(overlap, -1); // Length of the string minus the last code + // point. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int inc = length16 - overlap; // Keep overlap+inc==length16. + for (;;) { + if (inc > rest) { + break; + } + // Try to match if the increment is not listed already. + if (!offsets.containsOffset(inc) && matches16CPB(s, pos - overlap, length, string, length16)) { + if (inc == rest) { + return length; // Reached the end of the string. + } + offsets.addOffset(inc); + } + if (overlap == 0) { + break; + } + --overlap; + ++inc; + } + } + } else /* SIMPLE */{ + int maxInc = 0, maxOverlap = 0; + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[i]; + // For longest match, we do need to try to match even an all-contained string + // to find the match from the earliest start. + + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-overlap..pos. + if (overlap >= LONG_SPAN) { + overlap = length16; + // Longest match: Need to match fully inside the code point span + // to find the match from the earliest start. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int inc = length16 - overlap; // Keep overlap+inc==length16. + for (;;) { + if (inc > rest || overlap < maxOverlap) { + break; + } + // Try to match if the string is longer or starts earlier. + if ((overlap > maxOverlap || /* redundant overlap==maxOverlap && */inc > maxInc) + && matches16CPB(s, pos - overlap, length, string, length16)) { + maxInc = inc; // Longest match from earliest start. + maxOverlap = overlap; + break; + } + --overlap; + ++inc; + } + } + + if (maxInc != 0 || maxOverlap != 0) { + // Longest-match algorithm, and there was a string match. + // Simply continue after it. + pos += maxInc; + rest -= maxInc; + if (rest == 0) { + return length; // Reached the end of the string. + } + spanLength = 0; // Match strings from after a string match. + continue; + } + } + // Finished trying to match all strings at pos. + + if (spanLength != 0 || pos == 0) { + // The position is after an unlimited code point span (spanLength!=0), + // not after a string match. + // The only position where spanLength==0 after a span is pos==0. + // Otherwise, an unlimited code point span is only tried again when no + // strings match, and if such a non-initial span fails we stop. + if (offsets.isEmpty()) { + return pos; // No strings matched after a span. + } + // Match strings from after the next string match. + } else { + // The position is after a string match (or a single code point). + if (offsets.isEmpty()) { + // No more strings matched after a previous string match. + // Try another code point span from after the last string match. + spanLimit = spanSet.span(s, pos, SpanCondition.CONTAINED); + spanLength = spanLimit - pos; + if (spanLength == rest || // Reached the end of the string, or + spanLength == 0 // neither strings nor span progressed. + ) { + return spanLimit; + } + pos += spanLength; + rest -= spanLength; + continue; // spanLength>0: Match strings from after a span. + } else { + // Try to match only one code point from after a string match if some + // string matched beyond it, so that we try all possible positions + // and don't overshoot. + spanLength = spanOne(spanSet, s, pos, rest); + if (spanLength > 0) { + if (spanLength == rest) { + return length; // Reached the end of the string. + } + // Match strings after this code point. + // There cannot be any increments below it because UnicodeSet strings + // contain multiple code points. + pos += spanLength; + rest -= spanLength; + offsets.shift(spanLength); + spanLength = 0; + continue; // Match strings from after a single code point. + } + // Match strings from after the next string match. + } + } + int minOffset = offsets.popMinimum(null); + pos += minOffset; + rest -= minOffset; + spanLength = 0; // Match strings from after a string match. + } + } + + /** + * Spans a string and counts the smallest number of set elements on any path across the span. + * + * <p>For proper counting, we cannot ignore strings that are fully contained in code point spans. + * + * <p>If the set does not have any fully-contained strings, then we could optimize this + * like span(), but such sets are likely rare, and this is at least still linear. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @param outCount The count + * @return the limit (exclusive end) of the span + */ + public int spanAndCount(CharSequence s, int start, SpanCondition spanCondition, + OutputInt outCount) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNot(s, start, outCount); + } + // Consider strings; they may overlap with the span, + // and they may result in a smaller count that with just code points. + if (spanCondition == SpanCondition.CONTAINED) { + return spanContainedAndCount(s, start, outCount); + } + // SIMPLE (not synchronized, does not use offsets) + int stringsLength = strings.size(); + int length = s.length(); + int pos = start; + int rest = length - start; + int count = 0; + while (rest != 0) { + // Try to match the next code point. + int cpLength = spanOne(spanSet, s, pos, rest); + int maxInc = (cpLength > 0) ? cpLength : 0; + // Try to match all of the strings. + for (int i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + if (maxInc < length16 && length16 <= rest && + matches16CPB(s, pos, length, string, length16)) { + maxInc = length16; + } + } + // We are done if there is no match beyond pos. + if (maxInc == 0) { + outCount.value = count; + return pos; + } + // Continue from the longest match. + ++count; + pos += maxInc; + rest -= maxInc; + } + outCount.value = count; + return pos; + } + + private synchronized int spanContainedAndCount(CharSequence s, int start, OutputInt outCount) { + // Use offset list to try all possibilities. + offsets.setMaxLength(maxLength16); + int stringsLength = strings.size(); + int length = s.length(); + int pos = start; + int rest = length - start; + int count = 0; + while (rest != 0) { + // Try to match the next code point. + int cpLength = spanOne(spanSet, s, pos, rest); + if (cpLength > 0) { + offsets.addOffsetAndCount(cpLength, count + 1); + } + // Try to match all of the strings. + for (int i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + // Note: If the strings were sorted by length, then we could also + // avoid trying to match if there is already a match of the same length. + if (length16 <= rest && !offsets.hasCountAtOffset(length16, count + 1) && + matches16CPB(s, pos, length, string, length16)) { + offsets.addOffsetAndCount(length16, count + 1); + } + } + // We are done if there is no match beyond pos. + if (offsets.isEmpty()) { + outCount.value = count; + return pos; + } + // Continue from the nearest match. + int minOffset = offsets.popMinimum(outCount); + count = outCount.value; + pos += minOffset; + rest -= minOffset; + } + outCount.value = count; + return pos; + } + + /** + * Span a string backwards. + * + * @param s The string to be spanned + * @param spanCondition The span condition + * @return The string index which starts the span (i.e. inclusive). + */ + public synchronized int spanBack(CharSequence s, int length, SpanCondition spanCondition) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNotBack(s, length); + } + int pos = spanSet.spanBack(s, length, SpanCondition.CONTAINED); + if (pos == 0) { + return 0; + } + int spanLength = length - pos; + + // Consider strings; they may overlap with the span. + int initSize = 0; + if (spanCondition == SpanCondition.CONTAINED) { + // Use offset list to try all possibilities. + initSize = maxLength16; + } + offsets.setMaxLength(initSize); + int i, stringsLength = strings.size(); + int spanBackLengthsOffset = 0; + if (all) { + spanBackLengthsOffset = stringsLength; + } + for (;;) { + if (spanCondition == SpanCondition.CONTAINED) { + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[spanBackLengthsOffset + i]; + if (overlap == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-(length16-overlap)..pos-length16. + if (overlap >= LONG_SPAN) { + overlap = length16; + // While contained: No point matching fully inside the code point span. + int len1 = 0; + len1 = string.offsetByCodePoints(0, 1); + overlap -= len1; // Length of the string minus the first code point. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int dec = length16 - overlap; // Keep dec+overlap==length16. + for (;;) { + if (dec > pos) { + break; + } + // Try to match if the decrement is not listed already. + if (!offsets.containsOffset(dec) && matches16CPB(s, pos - dec, length, string, length16)) { + if (dec == pos) { + return 0; // Reached the start of the string. + } + offsets.addOffset(dec); + } + if (overlap == 0) { + break; + } + --overlap; + ++dec; + } + } + } else /* SIMPLE */{ + int maxDec = 0, maxOverlap = 0; + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[spanBackLengthsOffset + i]; + // For longest match, we do need to try to match even an all-contained string + // to find the match from the latest end. + + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-(length16-overlap)..pos-length16. + if (overlap >= LONG_SPAN) { + overlap = length16; + // Longest match: Need to match fully inside the code point span + // to find the match from the latest end. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int dec = length16 - overlap; // Keep dec+overlap==length16. + for (;;) { + if (dec > pos || overlap < maxOverlap) { + break; + } + // Try to match if the string is longer or ends later. + if ((overlap > maxOverlap || /* redundant overlap==maxOverlap && */dec > maxDec) + && matches16CPB(s, pos - dec, length, string, length16)) { + maxDec = dec; // Longest match from latest end. + maxOverlap = overlap; + break; + } + --overlap; + ++dec; + } + } + + if (maxDec != 0 || maxOverlap != 0) { + // Longest-match algorithm, and there was a string match. + // Simply continue before it. + pos -= maxDec; + if (pos == 0) { + return 0; // Reached the start of the string. + } + spanLength = 0; // Match strings from before a string match. + continue; + } + } + // Finished trying to match all strings at pos. + + if (spanLength != 0 || pos == length) { + // The position is before an unlimited code point span (spanLength!=0), + // not before a string match. + // The only position where spanLength==0 before a span is pos==length. + // Otherwise, an unlimited code point span is only tried again when no + // strings match, and if such a non-initial span fails we stop. + if (offsets.isEmpty()) { + return pos; // No strings matched before a span. + } + // Match strings from before the next string match. + } else { + // The position is before a string match (or a single code point). + if (offsets.isEmpty()) { + // No more strings matched before a previous string match. + // Try another code point span from before the last string match. + int oldPos = pos; + pos = spanSet.spanBack(s, oldPos, SpanCondition.CONTAINED); + spanLength = oldPos - pos; + if (pos == 0 || // Reached the start of the string, or + spanLength == 0 // neither strings nor span progressed. + ) { + return pos; + } + continue; // spanLength>0: Match strings from before a span. + } else { + // Try to match only one code point from before a string match if some + // string matched beyond it, so that we try all possible positions + // and don't overshoot. + spanLength = spanOneBack(spanSet, s, pos); + if (spanLength > 0) { + if (spanLength == pos) { + return 0; // Reached the start of the string. + } + // Match strings before this code point. + // There cannot be any decrements below it because UnicodeSet strings + // contain multiple code points. + pos -= spanLength; + offsets.shift(spanLength); + spanLength = 0; + continue; // Match strings from before a single code point. + } + // Match strings from before the next string match. + } + } + pos -= offsets.popMinimum(null); + spanLength = 0; // Match strings from before a string match. + } + } + + /** + * Algorithm for spanNot()==span(SpanCondition.NOT_CONTAINED) + * + * Theoretical algorithm: + * - Iterate through the string, and at each code point boundary: + * + If the code point there is in the set, then return with the current position. + * + If a set string matches at the current position, then return with the current position. + * + * Optimized implementation: + * + * (Same assumption as for span() above.) + * + * Create and cache a spanNotSet which contains + * all of the single code points of the original set but none of its strings. + * For each set string add its initial code point to the spanNotSet. + * (Also add its final code point for spanNotBack().) + * + * - Loop: + * + Do spanLength=spanNotSet.span(SpanCondition.NOT_CONTAINED). + * + If the current code point is in the original set, then return the current position. + * + If any set string matches at the current position, then return the current position. + * + If there is no match at the current position, neither for the code point + * there nor for any set string, then skip this code point and continue the loop. + * This happens for set-string-initial code points that were added to spanNotSet + * when there is not actually a match for such a set string. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param outCount If not null: Receives the number of code points across the span. + * @return the limit (exclusive end) of the span + */ + private int spanNot(CharSequence s, int start, OutputInt outCount) { + int length = s.length(); + int pos = start, rest = length - start; + int stringsLength = strings.size(); + int count = 0; + do { + // Span until we find a code point from the set, + // or a code point that starts or ends some string. + int spanLimit; + if (outCount == null) { + spanLimit = spanNotSet.span(s, pos, SpanCondition.NOT_CONTAINED); + } else { + spanLimit = spanNotSet.spanAndCount(s, pos, SpanCondition.NOT_CONTAINED, outCount); + outCount.value = count = count + outCount.value; + } + if (spanLimit == length) { + return length; // Reached the end of the string. + } + pos = spanLimit; + rest = length - spanLimit; + + // Check whether the current code point is in the original set, + // without the string starts and ends. + int cpLength = spanOne(spanSet, s, pos, rest); + if (cpLength > 0) { + return pos; // There is a set element at pos. + } + + // Try to match the strings at pos. + for (int i = 0; i < stringsLength; ++i) { + if (spanLengths[i] == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + if (length16 <= rest && matches16CPB(s, pos, length, string, length16)) { + return pos; // There is a set element at pos. + } + } + + // The span(while not contained) ended on a string start/end which is + // not in the original set. Skip this code point and continue. + // cpLength<0 + pos -= cpLength; + rest += cpLength; + ++count; + } while (rest != 0); + if (outCount != null) { + outCount.value = count; + } + return length; // Reached the end of the string. + } + + private int spanNotBack(CharSequence s, int length) { + int pos = length; + int i, stringsLength = strings.size(); + do { + // Span until we find a code point from the set, + // or a code point that starts or ends some string. + pos = spanNotSet.spanBack(s, pos, SpanCondition.NOT_CONTAINED); + if (pos == 0) { + return 0; // Reached the start of the string. + } + + // Check whether the current code point is in the original set, + // without the string starts and ends. + int cpLength = spanOneBack(spanSet, s, pos); + if (cpLength > 0) { + return pos; // There is a set element at pos. + } + + // Try to match the strings at pos. + for (i = 0; i < stringsLength; ++i) { + // Use spanLengths rather than a spanLengths pointer because + // it is easier and we only need to know whether the string is irrelevant + // which is the same in either array. + if (spanLengths[i] == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + if (length16 <= pos && matches16CPB(s, pos - length16, length, string, length16)) { + return pos; // There is a set element at pos. + } + } + + // The span(while not contained) ended on a string start/end which is + // not in the original set. Skip this code point and continue. + // cpLength<0 + pos += cpLength; + } while (pos != 0); + return 0; // Reached the start of the string. + } + + static short makeSpanLengthByte(int spanLength) { + // 0xfe==UnicodeSetStringSpan::LONG_SPAN + return spanLength < LONG_SPAN ? (short) spanLength : LONG_SPAN; + } + + // Compare strings without any argument checks. Requires length>0. + private static boolean matches16(CharSequence s, int start, final String t, int length) { + int end = start + length; + while (length-- > 0) { + if (s.charAt(--end) != t.charAt(length)) { + return false; + } + } + return true; + } + + /** + * Compare 16-bit Unicode strings (which may be malformed UTF-16) + * at code point boundaries. + * That is, each edge of a match must not be in the middle of a surrogate pair. + * @param s The string to match in. + * @param start The start index of s. + * @param limit The limit of the subsequence of s being spanned. + * @param t The substring to be matched in s. + * @param tlength The length of t. + */ + static boolean matches16CPB(CharSequence s, int start, int limit, final String t, int tlength) { + return matches16(s, start, t, tlength) + && !(0 < start && Character.isHighSurrogate(s.charAt(start - 1)) && + Character.isLowSurrogate(s.charAt(start))) + && !((start + tlength) < limit && Character.isHighSurrogate(s.charAt(start + tlength - 1)) && + Character.isLowSurrogate(s.charAt(start + tlength))); + } + + /** + * Does the set contain the next code point? + * If so, return its length; otherwise return its negative length. + */ + static int spanOne(final UnicodeSet set, CharSequence s, int start, int length) { + char c = s.charAt(start); + if (c >= 0xd800 && c <= 0xdbff && length >= 2) { + char c2 = s.charAt(start + 1); + if (UTF16.isTrailSurrogate(c2)) { + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + return set.contains(supplementary) ? 2 : -2; + } + } + return set.contains(c) ? 1 : -1; + } + + static int spanOneBack(final UnicodeSet set, CharSequence s, int length) { + char c = s.charAt(length - 1); + if (c >= 0xdc00 && c <= 0xdfff && length >= 2) { + char c2 = s.charAt(length - 2); + if (UTF16.isLeadSurrogate(c2)) { + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + return set.contains(supplementary) ? 2 : -2; + } + } + return set.contains(c) ? 1 : -1; + } + + /** + * Helper class for UnicodeSetStringSpan. + * + * <p>List of offsets from the current position from where to try matching + * a code point or a string. + * Stores offsets rather than indexes to simplify the code and use the same list + * for both increments (in span()) and decrements (in spanBack()). + * + * <p>Assumption: The maximum offset is limited, and the offsets that are stored at any one time + * are relatively dense, that is, + * there are normally no gaps of hundreds or thousands of offset values. + * + * <p>This class optionally also tracks the minimum non-negative count for each position, + * intended to count the smallest number of elements of any path leading to that position. + * + * <p>The implementation uses a circular buffer of count integers, + * each indicating whether the corresponding offset is in the list, + * and its path element count. + * This avoids inserting into a sorted list of offsets (or absolute indexes) + * and physically moving part of the list. + * + * <p>Note: In principle, the caller should setMaxLength() to + * the maximum of the max string length and U16_LENGTH/U8_LENGTH + * to account for "long" single code points. + * + * <p>Note: An earlier version did not track counts and stored only byte flags. + * With boolean flags, if maxLength were guaranteed to be no more than 32 or 64, + * the list could be stored as bit flags in a single integer. + * Rather than handling a circular buffer with a start list index, + * the integer would simply be shifted when lower offsets are removed. + * UnicodeSet does not have a limit on the lengths of strings. + */ + private static final class OffsetList { + private int[] list; + private int length; + private int start; + + public OffsetList() { + list = new int[16]; // default size + } + + public void setMaxLength(int maxLength) { + if (maxLength > list.length) { + list = new int[maxLength]; + } + clear(); + } + + public void clear() { + for (int i = list.length; i-- > 0;) { + list[i] = 0; + } + start = length = 0; + } + + public boolean isEmpty() { + return (length == 0); + } + + /** + * Reduces all stored offsets by delta, used when the current position moves by delta. + * There must not be any offsets lower than delta. + * If there is an offset equal to delta, it is removed. + * + * @param delta [1..maxLength] + */ + public void shift(int delta) { + int i = start + delta; + if (i >= list.length) { + i -= list.length; + } + if (list[i] != 0) { + list[i] = 0; + --length; + } + start = i; + } + + /** + * Adds an offset. The list must not contain it yet. + * @param offset [1..maxLength] + */ + public void addOffset(int offset) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + assert list[i] == 0; + list[i] = 1; + ++length; + } + + /** + * Adds an offset and updates its count. + * The list may already contain the offset. + * @param offset [1..maxLength] + */ + public void addOffsetAndCount(int offset, int count) { + assert count > 0; + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + if (list[i] == 0) { + list[i] = count; + ++length; + } else if (count < list[i]) { + list[i] = count; + } + } + + /** + * @param offset [1..maxLength] + */ + public boolean containsOffset(int offset) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + return list[i] != 0; + } + + /** + * @param offset [1..maxLength] + */ + public boolean hasCountAtOffset(int offset, int count) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + int oldCount = list[i]; + return oldCount != 0 && oldCount <= count; + } + + /** + * Finds the lowest stored offset from a non-empty list, removes it, + * and reduces all other offsets by this minimum. + * @return min=[1..maxLength] + */ + public int popMinimum(OutputInt outCount) { + // Look for the next offset in list[start+1..list.length-1]. + int i = start, result; + while (++i < list.length) { + int count = list[i]; + if (count != 0) { + list[i] = 0; + --length; + result = i - start; + start = i; + if (outCount != null) { outCount.value = count; } + return result; + } + } + // i==list.length + + // Wrap around and look for the next offset in list[0..start]. + // Since the list is not empty, there will be one. + result = list.length - start; + i = 0; + int count; + while ((count = list[i]) == 0) { + ++i; + } + list[i] = 0; + --length; + start = i; + if (outCount != null) { outCount.value = count; } + return result + i; + } + } +} diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/Utility.java b/jdk/src/java.base/share/classes/sun/text/normalizer/Utility.java index 59fb57189c0..37a22ec1ea0 100644 --- a/jdk/src/java.base/share/classes/sun/text/normalizer/Utility.java +++ b/jdk/src/java.base/share/classes/sun/text/normalizer/Utility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * 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,47 +24,26 @@ */ /* ******************************************************************************* - * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * - * * - * The original version of this source code and documentation is copyrighted * - * and owned by IBM, These materials are provided under terms of a License * - * Agreement between IBM and Sun. This technology is protected by multiple * - * US and International patents. This notice and attribution to IBM may not * - * to removed. * + * Copyright (C) 1996-2011, International Business Machines Corporation and * + * others. All Rights Reserved. * ******************************************************************************* */ package sun.text.normalizer; -public final class Utility { +import java.io.IOException; +import java.util.Locale; - /** - * Convenience utility to compare two Object[]s - * Ought to be in System. - * @param len the length to compare. - * The start indices and start+len must be valid. - */ - public final static boolean arrayRegionMatches(char[] source, int sourceStart, - char[] target, int targetStart, - int len) - { - int sourceEnd = sourceStart + len; - int delta = targetStart - sourceStart; - for (int i = sourceStart; i < sourceEnd; i++) { - if (source[i]!=target[i + delta]) - return false; - } - return true; - } +final class Utility { /** * Convert characters outside the range U+0020 to U+007F to * Unicode escapes, and convert backslash to a double backslash. */ public static final String escape(String s) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); for (int i=0; i<s.length(); ) { - int c = UTF16.charAt(s, i); + int c = Character.codePointAt(s, i); i += UTF16.getCharCount(c); if (c >= ' ' && c <= 0x007F) { if (c == '\\') { @@ -75,7 +54,7 @@ public final class Utility { } else { boolean four = c <= 0xFFFF; buf.append(four ? "\\u" : "\\U"); - hex(c, four ? 4 : 8, buf); + buf.append(hex(c, four ? 4 : 8)); } } return buf.toString(); @@ -124,7 +103,7 @@ public final class Utility { } /* Fetch first UChar after '\\' */ - c = UTF16.charAt(s, offset); + c = Character.codePointAt(s, offset); offset += UTF16.getCharCount(c); /* Convert hexadecimal and octal escapes */ @@ -143,7 +122,7 @@ public final class Utility { maxDig = 8; } else { maxDig = 2; - } + } break; default: dig = UCharacter.digit(c, 8); @@ -175,7 +154,7 @@ public final class Utility { return -1; } ++offset; - } + } if (result < 0 || result >= 0x110000) { return -1; } @@ -184,7 +163,7 @@ public final class Utility { // escape or as a literal. If so, join them up into a // supplementary. if (offset < length && - UTF16.isLeadSurrogate((char) result)) { + UTF16.isLeadSurrogate((char) result)) { int ahead = offset+1; c = s.charAt(offset); // [sic] get 16-bit code unit if (c == '\\' && ahead < length) { @@ -194,8 +173,8 @@ public final class Utility { } if (UTF16.isTrailSurrogate((char) c)) { offset = ahead; - result = UCharacterProperty.getRawSupplementary( - (char) result, (char) c); + result = UCharacterProperty.getRawSupplementary( + (char) result, (char) c); } } offset16[0] = offset; @@ -226,39 +205,22 @@ public final class Utility { } /** - * Convert a integer to size width hex uppercase digits. - * E.g., {@code hex('a', 4, str) => "0041"}. - * Append the output to the given StringBuffer. - * If width is too small to fit, nothing will be appended to output. + * Supplies a zero-padded hex representation of an integer (without 0x) */ - public static StringBuffer hex(int ch, int width, StringBuffer output) { - return appendNumber(output, ch, 16, width); - } - - /** - * Convert a integer to size width (minimum) hex uppercase digits. - * E.g., {@code hex('a', 4, str) => "0041"}. If the integer requires more - * than width digits, more will be used. - */ - public static String hex(int ch, int width) { - StringBuffer buf = new StringBuffer(); - return appendNumber(buf, ch, 16, width).toString(); - } - - /** - * Skip over a sequence of zero or more white space characters - * at pos. Return the index of the first non-white-space character - * at or after pos, or str.length(), if there is none. - */ - public static int skipWhitespace(String str, int pos) { - while (pos < str.length()) { - int c = UTF16.charAt(str, pos); - if (!UCharacterProperty.isRuleWhiteSpace(c)) { - break; - } - pos += UTF16.getCharCount(c); + static public String hex(long i, int places) { + if (i == Long.MIN_VALUE) return "-8000000000000000"; + boolean negative = i < 0; + if (negative) { + i = -i; } - return pos; + String result = Long.toString(i, 16).toUpperCase(Locale.ENGLISH); + if (result.length() < places) { + result = "0000000000000000".substring(result.length(),places) + result; + } + if (negative) { + return '-' + result; + } + return result; } static final char DIGITS[] = { @@ -268,118 +230,44 @@ public final class Utility { 'U', 'V', 'W', 'X', 'Y', 'Z' }; - /** - * Append the digits of a positive integer to the given - * <code>StringBuffer</code> in the given radix. This is - * done recursively since it is easiest to generate the low- - * order digit first, but it must be appended last. - * - * @param result is the <code>StringBuffer</code> to append to - * @param n is the positive integer - * @param radix is the radix, from 2 to 36 inclusive - * @param minDigits is the minimum number of digits to append. - */ - private static void recursiveAppendNumber(StringBuffer result, int n, - int radix, int minDigits) - { - int digit = n % radix; - - if (n >= radix || minDigits > 1) { - recursiveAppendNumber(result, n / radix, radix, minDigits - 1); - } - - result.append(DIGITS[digit]); - } - - /** - * Append a number to the given StringBuffer in the given radix. - * Standard digits '0'-'9' are used and letters 'A'-'Z' for - * radices 11 through 36. - * @param result the digits of the number are appended here - * @param n the number to be converted to digits; may be negative. - * If negative, a '-' is prepended to the digits. - * @param radix a radix from 2 to 36 inclusive. - * @param minDigits the minimum number of digits, not including - * any '-', to produce. Values less than 2 have no effect. One - * digit is always emitted regardless of this parameter. - * @return a reference to result - */ - public static StringBuffer appendNumber(StringBuffer result, int n, - int radix, int minDigits) - throws IllegalArgumentException - { - if (radix < 2 || radix > 36) { - throw new IllegalArgumentException("Illegal radix " + radix); - } - - - int abs = n; - - if (n < 0) { - abs = -n; - result.append("-"); - } - - recursiveAppendNumber(result, abs, radix, minDigits); - - return result; - } - /** * Return true if the character is NOT printable ASCII. The tab, * newline and linefeed characters are considered unprintable. */ public static boolean isUnprintable(int c) { + //0x20 = 32 and 0x7E = 126 return !(c >= 0x20 && c <= 0x7E); } /** - * Escape unprintable characters using {@code <backslash>uxxxx} notation - * for U+0000 to U+FFFF and {@code <backslash>Uxxxxxxxx} for U+10000 and + * Escape unprintable characters using <backslash>uxxxx notation + * for U+0000 to U+FFFF and <backslash>Uxxxxxxxx for U+10000 and * above. If the character is printable ASCII, then do nothing * and return FALSE. Otherwise, append the escaped notation and * return TRUE. */ - public static boolean escapeUnprintable(StringBuffer result, int c) { - if (isUnprintable(c)) { - result.append('\\'); - if ((c & ~0xFFFF) != 0) { - result.append('U'); - result.append(DIGITS[0xF&(c>>28)]); - result.append(DIGITS[0xF&(c>>24)]); - result.append(DIGITS[0xF&(c>>20)]); - result.append(DIGITS[0xF&(c>>16)]); - } else { - result.append('u'); + public static <T extends Appendable> boolean escapeUnprintable(T result, int c) { + try { + if (isUnprintable(c)) { + result.append('\\'); + if ((c & ~0xFFFF) != 0) { + result.append('U'); + result.append(DIGITS[0xF&(c>>28)]); + result.append(DIGITS[0xF&(c>>24)]); + result.append(DIGITS[0xF&(c>>20)]); + result.append(DIGITS[0xF&(c>>16)]); + } else { + result.append('u'); + } + result.append(DIGITS[0xF&(c>>12)]); + result.append(DIGITS[0xF&(c>>8)]); + result.append(DIGITS[0xF&(c>>4)]); + result.append(DIGITS[0xF&c]); + return true; } - result.append(DIGITS[0xF&(c>>12)]); - result.append(DIGITS[0xF&(c>>8)]); - result.append(DIGITS[0xF&(c>>4)]); - result.append(DIGITS[0xF&c]); - return true; + return false; + } catch (IOException e) { + throw new IllegalArgumentException(e); } - return false; } - - /** - * Similar to StringBuffer.getChars, version 1.3. - * Since JDK 1.2 implements StringBuffer.getChars differently, this method - * is here to provide consistent results. - * To be removed after JDK 1.2 ceased to be the reference platform. - * @param src source string buffer - * @param srcBegin offset to the start of the src to retrieve from - * @param srcEnd offset to the end of the src to retrieve from - * @param dst char array to store the retrieved chars - * @param dstBegin offset to the start of the destination char array to - * store the retrieved chars - */ - public static void getChars(StringBuffer src, int srcBegin, int srcEnd, - char dst[], int dstBegin) - { - if (srcBegin == srcEnd) { - return; - } - src.getChars(srcBegin, srcEnd, dst, dstBegin); - } - } diff --git a/jdk/src/java.base/share/classes/sun/text/resources/nfc.icu b/jdk/src/java.base/share/classes/sun/text/resources/nfc.icu new file mode 100644 index 0000000000000000000000000000000000000000..1cd67e08581084c7ef7ddc43f0741db786193af8 GIT binary patch literal 34464 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 literal 0 HcmV?d00001 diff --git a/jdk/src/java.base/share/classes/sun/text/resources/nfkc.icu b/jdk/src/java.base/share/classes/sun/text/resources/nfkc.icu new file mode 100644 index 0000000000000000000000000000000000000000..a88ac684416dcfa32ba516d8fef91640ef762ef5 GIT binary patch literal 53504 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 C9E9Bf literal 0 HcmV?d00001 diff --git a/jdk/src/java.base/share/classes/sun/text/resources/nfkc_cf.icu b/jdk/src/java.base/share/classes/sun/text/resources/nfkc_cf.icu new file mode 100644 index 0000000000000000000000000000000000000000..b23f0d79d04aa6131d7f6bc6adba816214d20897 GIT binary patch literal 50288 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 SH}>ED_4h?>y7PD8fBylD(9F&N literal 0 HcmV?d00001 diff --git a/jdk/src/java.base/share/classes/sun/text/resources/ubidi.icu b/jdk/src/java.base/share/classes/sun/text/resources/ubidi.icu index 3c545bd7a450e407f4755effb75f68886faa43e5..73774edc2452e95b0c92dbe32ff58c0ed0ba2f0c 100644 GIT binary patch literal 22976 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 literal 19924 zcmeHP4~Sex8J~SK@6T@Uk~OAja*fSpdr2;7<0W^sNf7jErCQ-kgkqGUMrtVsRjZ;> z3U*UyiNfhAR)Y|{f+?wKV-iw`r0NxGNx(>gtq?0Au~mrGqPB_HB*ppWd*9B?doyp} zyF+Q^X4v`u{k}glZ{FM8x#d{@?^m&fjMZ4c-Z%dK@fr(*sK(6JWNhpZV;^cuWglZv zKV!+`Ccw*YVh3;g;`p761uGb9NZ8dIgB`(Surrtn_5}Nb!@+dW_V#Ck-vqx4POJXM z;4cdIw+{Mzhr<XLIpYa$@CCe&xA+>qj&I=a<saai`Bwf3{uzEZ{}R8CZ|6JsxA^xZ zuEBpOb&v9Wd_O<Tr}<HSjGyGE_*qHM@mCbRz~A6U1s7NFY0(VYVzF2%$7{uPVnot+ zi<`NsU-~I3ZiSk}X0cV#+r=GHx=Vacj$aX96Ay~{N<SeU7Q4jmO#L_u=O~_#5uQZ6 z_*pqW@v9VnTpZ`m^XFxR--;K+lj244=g+2ym&L0ocV1i$!=N4ZgbN83E)AE7X1FRG z3O7j0d*tipj_ua)Bg89uI{dgLTeAs29gc^e4Zj@T7d{YvBm7SIgYXftBYZ485dKs~ zeOg?G9v%x%hNr@_;h)1-!VBT0NJKqBJ6aGeQC23$P0=!OIa&po#Ovtg8lxf5M#E~{ zsK(LggW3AXGujeujXo9K6@5PXYIJ|}Q1s2{d(p0FxAK$g@9xnd)JIRH_S4Zb(XWAz zo&(Pi>h1LCh3IT_F8YVE|65(jU!;C2zO430TnpN9J${=Um&D7-8m|COoDY6ZnmPLB zTLHMzZ@#MLDw<n?xfPgOf&Z@+i0krcyD2}X_<GRA>+u~~j7!vON|R#an_~GHAl|HW zAB{gL`8(sggErq6e*vS#_r}|m^+A3#o<JRq@pp-vqjM|pR$PJlQ2oZBU6-HZ%fITk znAo@CtmkT;=?cU<<Ei*Z@|&`^$9u>Y?~f0~PsPu~N8=Nyi=T`C5bTU!ivNoFWA!Ya zX)P|l_>%lyBtLg20<8RL7sk}7Z~pM@KkZ2maY&Pe$>NNr-<Hcr$)Fc?H2zq!E^3BD z$wpQ2zGM`rly5QXoIRg>c=j=Lgyc5O=egwe<c?$<^y*rq@1!01-n>T{O>%$GP9Bo4 z2juJP^7ZZHVeh(juIMZg);>>mWuwXO=qF%~Axm~A@?0QM=Q7C=-+biG{H1&ygOh;d zWO7Q5XOnXfL9NuwQhqhL7^{;ZIOhOuo#Q%2aOR|NA@jwrrmx5K`Sq(*UshK=Jzv99 zw$t@hsQvGa-m}88h6OC!6Be_C)#aGAm~t%bh-=8BNTIsq);0bPGG~!`Me-Ol-y_!8 zB2gy*3CEa~o8dh>e|tuzRF;=>NoOzAY}AY<VLYg0SQ%IWs1xTKFsAG%Rh#>aW^1IF ziNBhW5rgJ|^=C%_W_6~l1DRUni#-u@fX%K`eu$QBrUvb%CX4pVelNRre+0Kh#})Dq z40f!UNDu?#=&>d>v*{tD-mCUOuev*W<?{e#cb&b`ihWGdiL{SNimx$Ap=%3ivUF{V zB>jYv-C12)s@|kR&8atygf;YbYNSj^slp;^d(2FlP}StKj2UYN)?WFt=NZcDVrpRB zLDpLE%RjY)bY%e#SE;B!p|ax4AR2a>Db`LBp~fT%Uoe^#`gy3q6%AresE*OIBiKj> zoR&3*_M%yqwYlpr_IBNaH?gWcpBdufleEE>SG?0Hn)&P@o+w~kwP$tPjkzG7*T8H+ zi@unh;*6<XNY@Z4T)T<FeW}-+=2DH~opQkacrL94e;p%R0fixiZ6~Wq0WtG78(-Hv zvXzvN-)$c7S;}sv+|Aqe%uA*}@j$75qIpkK(;bg75vS4SN}BOpyy=y<n`@G{cGKW2 zVWc{<9{F|1YqCCm+3)MO<fG9O4JdpLpIyV5>lh@vR|K@~=C|bW<_u<2Kh`p3B`~Eb zHD%|8^Dnzo(Hnheq_VPml<Y(aS48vianHJaC^FEQwCaA4N4?-XvHD(IF0WZ>me+SB zMmOh@#iDF_xDnm7-Kr*kI}=La3-;>G^ui3?V(2=2NUXz*49ITPb+h}jk-l8@_Wh3% zMF2XRX9D=wVW`?F>{<w2Zl-n-cs0<IMjJs_h^#iXvG82M>*ZQc`i4_xEiem32Pxld zo$W!_3+k9{bI+xkwptDD`F4u|>w&94BVG+$C(;o$qmj;}VAryVuEN_j(eCg?(D{ff zLi%iF^=1y>yH%HsOLId#NkILLauNk3=Jxv#MrR;zlbTn{jA++mOFE|+$%oNs&5@th zROR6Q#Cyr@S!4r`GIn_Wy81z}Kny2S$s=hL|2-|w<CDF~zGQ#$c=8i@nuaItFs44~ z$vZ`eGBW9lX<eRLQ`aZpqyZ{VuT?Y8hvZL%)02Ps(_}|C?Wwz$=y{dryul0u?Gqn` zb)joXoZ;SK$p(~~xu*C|jVQ8bKkbqpb1JE+W02LXM)MkHbJ~kIv%>EFjb_?$Ki$)S zzF&3J$O<{^wn>R24f-&{7i?tLdWx+rh-#|O#o7w7vmJB62s_%ntHB2&5{9VhM>-e9 z%E+Q~PNs9!n$F+2)JjaIBUMcih}ttYC5lK$%mh-_LWnE{9O$5iNx1?zA_X3F6pJXu zAh{dGl{HZi!ITZ2c3ySri|Eo9?d9^BvyolTEtifmWc^7ls*W%Pl&+798Y|t2fLEB% zv^TfND}SPc!TZp@Zg}TmMDlh~SI)f7<#~_VoBKO=En&bLc2#lD=9n~Q12%{T5r85V zR|2E!Tx2JWiK05tM_Vu+MV++rP&^YueDRFPN?9=<jGCh=DI#4@TXt8fF?kMh+gfuT zc4dGw@qh%GY9mTsWFwjES!&v`nk>S;s)VQbCc4N5I6YU$G?~iuWW?-<0koEhqg)`9 zPRGn}_(U*rcI@=5$Ro&tpGHW^<Lviv8&^hxzv^|a9M*;FW3N)D;?69{PAg&3Jldh5 z>N*h}7@w``Gn8@_QGYJ<s(0#BvN>Pk0YN;`j+g67(PvGFXxgC`-LNt(m*pV39jUCR zjVl)etMrd{%<>XOEQ9yw28*wem(T9jm+?Z3+dr$Noj@m0BqMdz@1IdNwwCF8Gtp}2 z2~dl^^K?|3gKuS3nr|g_ja8y$&lv1=B&l0O!V&F;*LL!-skV3HaMt7vX#YA83Me9N zs+5@_A1$xRxTGTBFe4}^CmL-Dbu_wc?wqLAHqBA2Y7~BPK)(hsDR*j3gvsk)1XSl> zZ+G+3rzmdD?~k$Zn)pY$zf5YbqwQ&0kT?BYJp8^fl290xo!<F?rl(Kxd`C&}%)(zo z>Zg}~eq}5NRYdxQrOcn^`5*nh6tkr{^_+0!%8mMj4xgO%8Z*alY=6w40}ghK{mG$R zP7`J4BS|Ajlcj_(@0IF&L*9$H1Ci<ov@f-$97oX*?S29jN3v&X{?4yDPqU-h(5l(g z&S*<E(kGemfrmDwMtdL}AT*DhjVvQ&Blw@#m=9u_J|Go0LKmYbY93{tOao8xh=K?4 zNb@oL8uIibv<0pz;%D}puy;i_N$0J^$?vkITNNw?_4v5X(W>gYy<5PF6=8~36eduF z=w^p?E%I+T{we}1P_03RvaK7^thQV2CN|GwMOtr0D_gDUqa)c|aV#5KRf7CwYVgO^ z-r4o=`}iynfovEpKa$-~$;XW#>r5zql0E47?Bf26>(XYQ+*M^)%qlv1w)<$8SV_P9 zuT7)Lwxpd*m0!YSx-2$1qkp7Q@2`*6x7FM7kH}MH{oT0wRDHUB2D;l`Lfg;wO4N~H zs&!?pza{^7QEO)~-FlR>)}G)@>oMNn+RL`Jj@Qn#{u!{=t3iM3wP3V$A=uXXS8cTQ zdTm?lVy)e}RGVsDu1&YzVC~h1+34!?Y--JEc4p0sY<kU0HMZtYBaHK5KElP25Y1*Y zjt2$?2Uo6KyS7%FH?PrXu%6bUzNOc^eRyP~MA4!p!^v+c!^0yYZ89jdnA!lfL6xW0 zqgtyq@49)57A=~mTAys!$kxB4Ika%$y5Y1n-qnz0+;9UM@|6+~Xv^SA`R~A%Xc@VH zh4bep$%5-QUb%k#jT^4I`W?$w_tuxMSaof(=AGgEB#XD?O^dJS%u24*V67(0mlZEv sDvRxtE7xoe4m3G$G)9Jpqo_GJxXALK6LKpcSaWSpt8eMZ$iVP_05<14I{*Lx diff --git a/jdk/src/java.base/share/classes/sun/text/resources/unorm.icu b/jdk/src/java.base/share/classes/sun/text/resources/unorm.icu deleted file mode 100644 index 89bdace1e6f295231d6dbee401ede93ceac6b466..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126672 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℘qT56B4v$W1z0ow0)w6s=Qukgbmw(Zz1 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 TT#9imiwP3T1q;un>gxPImq5Ws diff --git a/jdk/src/java.base/share/classes/sun/text/resources/uprops.icu b/jdk/src/java.base/share/classes/sun/text/resources/uprops.icu index 17df38a04ff5050bbdb6efce6554bfc351805f6b..57c6806462c426b4b6f4b5a63ee6725817ac7dcd 100644 GIT binary patch literal 113360 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 literal 92804 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 Q%;0ed{&|eeP<V{}KZX;D!T<mO diff --git a/jdk/src/java.desktop/share/classes/java/awt/font/NumericShaper.java b/jdk/src/java.desktop/share/classes/java/awt/font/NumericShaper.java index 04c4487bd7f..aed4a05482d 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/font/NumericShaper.java +++ b/jdk/src/java.desktop/share/classes/java/awt/font/NumericShaper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -318,7 +318,17 @@ public final class NumericShaper implements java.io.Serializable { /** * The Meetei Mayek range with the Meetei Mayek digits. */ - MEETEI_MAYEK ('\uabf0', '\uabc0', '\uac00'); + MEETEI_MAYEK ('\uabf0', '\uabc0', '\uac00'), + /** + * The Sinhala range with the Sinhala digits. + * @since 1.9 + */ + SINHALA ('\u0de6', '\u0d80', '\u0e00'), + /** + * The Myanmar Extended-B range with the Myanmar Tai Laing digits. + * @since 1.9 + */ + MYANMAR_TAI_LAING ('\ua9f0', '\ua9e0', '\uaa00'); private static int toRangeIndex(Range script) { int index = script.ordinal(); @@ -624,15 +634,25 @@ public final class NumericShaper implements java.io.Serializable { 0x02e5, 0x02ee, 0x02ef, 0x0370, 0x0374, 0x0376, - 0x037e, 0x0386, + 0x0378, 0x037a, + 0x037e, 0x037f, + 0x0380, 0x0386, 0x0387, 0x0388, + 0x038b, 0x038c, + 0x038d, 0x038e, + 0x03a2, 0x03a3, 0x03f6, 0x03f7, 0x0483, 0x048a, - 0x058a, 0x05be, + 0x0530, 0x0531, + 0x0557, 0x0559, + 0x0560, 0x0561, + 0x0588, 0x0589, + 0x058a, 0x0590, + 0x0591, 0x05be, 0x05bf, 0x05c0, 0x05c1, 0x05c3, 0x05c4, 0x05c6, - 0x05c7, 0x05d0, + 0x05c7, 0x05c8, 0x0600, 0x0608, 0x0609, 0x060b, 0x060c, 0x060d, @@ -643,15 +663,15 @@ public final class NumericShaper implements java.io.Serializable { 0x06e7, 0x06ee, 0x06f0, 0x06fa, 0x0711, 0x0712, - 0x0730, 0x074d, + 0x0730, 0x074b, 0x07a6, 0x07b1, 0x07eb, 0x07f4, 0x07f6, 0x07fa, 0x0816, 0x081a, 0x081b, 0x0824, 0x0825, 0x0828, - 0x0829, 0x0830, - 0x0859, 0x085e, + 0x0829, 0x082e, + 0x0859, 0x085c, 0x08e4, 0x0903, 0x093a, 0x093b, 0x093c, 0x093d, @@ -660,57 +680,161 @@ public final class NumericShaper implements java.io.Serializable { 0x0951, 0x0958, 0x0962, 0x0964, 0x0981, 0x0982, - 0x09bc, 0x09bd, + 0x0984, 0x0985, + 0x098d, 0x098f, + 0x0991, 0x0993, + 0x09a9, 0x09aa, + 0x09b1, 0x09b2, + 0x09b3, 0x09b6, + 0x09ba, 0x09bd, 0x09c1, 0x09c7, + 0x09c9, 0x09cb, 0x09cd, 0x09ce, + 0x09cf, 0x09d7, + 0x09d8, 0x09dc, + 0x09de, 0x09df, 0x09e2, 0x09e6, 0x09f2, 0x09f4, 0x09fb, 0x0a03, - 0x0a3c, 0x0a3e, + 0x0a04, 0x0a05, + 0x0a0b, 0x0a0f, + 0x0a11, 0x0a13, + 0x0a29, 0x0a2a, + 0x0a31, 0x0a32, + 0x0a34, 0x0a35, + 0x0a37, 0x0a38, + 0x0a3a, 0x0a3e, 0x0a41, 0x0a59, + 0x0a5d, 0x0a5e, + 0x0a5f, 0x0a66, 0x0a70, 0x0a72, 0x0a75, 0x0a83, - 0x0abc, 0x0abd, + 0x0a84, 0x0a85, + 0x0a8e, 0x0a8f, + 0x0a92, 0x0a93, + 0x0aa9, 0x0aaa, + 0x0ab1, 0x0ab2, + 0x0ab4, 0x0ab5, + 0x0aba, 0x0abd, 0x0ac1, 0x0ac9, + 0x0aca, 0x0acb, 0x0acd, 0x0ad0, + 0x0ad1, 0x0ae0, 0x0ae2, 0x0ae6, 0x0af1, 0x0b02, - 0x0b3c, 0x0b3d, + 0x0b04, 0x0b05, + 0x0b0d, 0x0b0f, + 0x0b11, 0x0b13, + 0x0b29, 0x0b2a, + 0x0b31, 0x0b32, + 0x0b34, 0x0b35, + 0x0b3a, 0x0b3d, 0x0b3f, 0x0b40, 0x0b41, 0x0b47, + 0x0b49, 0x0b4b, 0x0b4d, 0x0b57, + 0x0b58, 0x0b5c, + 0x0b5e, 0x0b5f, 0x0b62, 0x0b66, - 0x0b82, 0x0b83, + 0x0b78, 0x0b83, + 0x0b84, 0x0b85, + 0x0b8b, 0x0b8e, + 0x0b91, 0x0b92, + 0x0b96, 0x0b99, + 0x0b9b, 0x0b9c, + 0x0b9d, 0x0b9e, + 0x0ba0, 0x0ba3, + 0x0ba5, 0x0ba8, + 0x0bab, 0x0bae, + 0x0bba, 0x0bbe, 0x0bc0, 0x0bc1, + 0x0bc3, 0x0bc6, + 0x0bc9, 0x0bca, 0x0bcd, 0x0bd0, + 0x0bd1, 0x0bd7, + 0x0bd8, 0x0be6, 0x0bf3, 0x0c01, + 0x0c04, 0x0c05, + 0x0c0d, 0x0c0e, + 0x0c11, 0x0c12, + 0x0c29, 0x0c2a, + 0x0c3a, 0x0c3d, 0x0c3e, 0x0c41, - 0x0c46, 0x0c58, + 0x0c45, 0x0c58, + 0x0c5a, 0x0c60, 0x0c62, 0x0c66, - 0x0c78, 0x0c7f, - 0x0cbc, 0x0cbd, + 0x0c70, 0x0c7f, + 0x0c80, 0x0c82, + 0x0c84, 0x0c85, + 0x0c8d, 0x0c8e, + 0x0c91, 0x0c92, + 0x0ca9, 0x0caa, + 0x0cb4, 0x0cb5, + 0x0cba, 0x0cbd, + 0x0cc5, 0x0cc6, + 0x0cc9, 0x0cca, 0x0ccc, 0x0cd5, + 0x0cd7, 0x0cde, + 0x0cdf, 0x0ce0, 0x0ce2, 0x0ce6, + 0x0cf0, 0x0cf1, + 0x0cf3, 0x0d02, + 0x0d04, 0x0d05, + 0x0d0d, 0x0d0e, + 0x0d11, 0x0d12, + 0x0d3b, 0x0d3d, 0x0d41, 0x0d46, + 0x0d49, 0x0d4a, 0x0d4d, 0x0d4e, + 0x0d4f, 0x0d57, + 0x0d58, 0x0d60, 0x0d62, 0x0d66, - 0x0dca, 0x0dcf, + 0x0d76, 0x0d79, + 0x0d80, 0x0d82, + 0x0d84, 0x0d85, + 0x0d97, 0x0d9a, + 0x0db2, 0x0db3, + 0x0dbc, 0x0dbd, + 0x0dbe, 0x0dc0, + 0x0dc7, 0x0dcf, 0x0dd2, 0x0dd8, + 0x0de0, 0x0de6, + 0x0df0, 0x0df2, + 0x0df5, 0x0e01, 0x0e31, 0x0e32, 0x0e34, 0x0e40, 0x0e47, 0x0e4f, + 0x0e5c, 0x0e81, + 0x0e83, 0x0e84, + 0x0e85, 0x0e87, + 0x0e89, 0x0e8a, + 0x0e8b, 0x0e8d, + 0x0e8e, 0x0e94, + 0x0e98, 0x0e99, + 0x0ea0, 0x0ea1, + 0x0ea4, 0x0ea5, + 0x0ea6, 0x0ea7, + 0x0ea8, 0x0eaa, + 0x0eac, 0x0ead, 0x0eb1, 0x0eb2, 0x0eb4, 0x0ebd, - 0x0ec8, 0x0ed0, + 0x0ebe, 0x0ec0, + 0x0ec5, 0x0ec6, + 0x0ec7, 0x0ed0, + 0x0eda, 0x0edc, + 0x0ee0, 0x0f00, 0x0f18, 0x0f1a, 0x0f35, 0x0f36, 0x0f37, 0x0f38, 0x0f39, 0x0f3e, - 0x0f71, 0x0f7f, + 0x0f48, 0x0f49, + 0x0f6d, 0x0f7f, 0x0f80, 0x0f85, 0x0f86, 0x0f88, 0x0f8d, 0x0fbe, 0x0fc6, 0x0fc7, + 0x0fcd, 0x0fce, + 0x0fdb, 0x1000, 0x102d, 0x1031, 0x1032, 0x1038, 0x1039, 0x103b, @@ -722,66 +846,119 @@ public final class NumericShaper implements java.io.Serializable { 0x1085, 0x1087, 0x108d, 0x108e, 0x109d, 0x109e, - 0x135d, 0x1360, + 0x10c6, 0x10c7, + 0x10c8, 0x10cd, + 0x10ce, 0x10d0, + 0x1249, 0x124a, + 0x124e, 0x1250, + 0x1257, 0x1258, + 0x1259, 0x125a, + 0x125e, 0x1260, + 0x1289, 0x128a, + 0x128e, 0x1290, + 0x12b1, 0x12b2, + 0x12b6, 0x12b8, + 0x12bf, 0x12c0, + 0x12c1, 0x12c2, + 0x12c6, 0x12c8, + 0x12d7, 0x12d8, + 0x1311, 0x1312, + 0x1316, 0x1318, + 0x135b, 0x1360, + 0x137d, 0x1380, 0x1390, 0x13a0, - 0x1400, 0x1401, + 0x13f5, 0x1401, 0x1680, 0x1681, 0x169b, 0x16a0, + 0x16f9, 0x1700, + 0x170d, 0x170e, 0x1712, 0x1720, 0x1732, 0x1735, + 0x1737, 0x1740, 0x1752, 0x1760, - 0x1772, 0x1780, + 0x176d, 0x176e, + 0x1771, 0x1780, 0x17b4, 0x17b6, 0x17b7, 0x17be, 0x17c6, 0x17c7, 0x17c9, 0x17d4, 0x17db, 0x17dc, 0x17dd, 0x17e0, - 0x17f0, 0x1810, + 0x17ea, 0x1810, + 0x181a, 0x1820, + 0x1878, 0x1880, 0x18a9, 0x18aa, - 0x1920, 0x1923, + 0x18ab, 0x18b0, + 0x18f6, 0x1900, + 0x191f, 0x1923, 0x1927, 0x1929, + 0x192c, 0x1930, 0x1932, 0x1933, 0x1939, 0x1946, - 0x19de, 0x1a00, + 0x196e, 0x1970, + 0x1975, 0x1980, + 0x19ac, 0x19b0, + 0x19ca, 0x19d0, + 0x19db, 0x1a00, 0x1a17, 0x1a19, + 0x1a1b, 0x1a1e, 0x1a56, 0x1a57, 0x1a58, 0x1a61, 0x1a62, 0x1a63, 0x1a65, 0x1a6d, 0x1a73, 0x1a80, - 0x1b00, 0x1b04, + 0x1a8a, 0x1a90, + 0x1a9a, 0x1aa0, + 0x1aae, 0x1b04, 0x1b34, 0x1b35, 0x1b36, 0x1b3b, 0x1b3c, 0x1b3d, 0x1b42, 0x1b43, + 0x1b4c, 0x1b50, 0x1b6b, 0x1b74, - 0x1b80, 0x1b82, + 0x1b7d, 0x1b82, 0x1ba2, 0x1ba6, 0x1ba8, 0x1baa, - 0x1bab, 0x1bac, + 0x1bab, 0x1bae, 0x1be6, 0x1be7, 0x1be8, 0x1bea, 0x1bed, 0x1bee, 0x1bef, 0x1bf2, + 0x1bf4, 0x1bfc, 0x1c2c, 0x1c34, 0x1c36, 0x1c3b, - 0x1cd0, 0x1cd3, + 0x1c4a, 0x1c4d, + 0x1c80, 0x1cc0, + 0x1cc8, 0x1cd3, 0x1cd4, 0x1ce1, 0x1ce2, 0x1ce9, 0x1ced, 0x1cee, 0x1cf4, 0x1cf5, + 0x1cf7, 0x1d00, 0x1dc0, 0x1e00, + 0x1f16, 0x1f18, + 0x1f1e, 0x1f20, + 0x1f46, 0x1f48, + 0x1f4e, 0x1f50, + 0x1f58, 0x1f59, + 0x1f5a, 0x1f5b, + 0x1f5c, 0x1f5d, + 0x1f5e, 0x1f5f, + 0x1f7e, 0x1f80, + 0x1fb5, 0x1fb6, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc2, + 0x1fc5, 0x1fc6, 0x1fcd, 0x1fd0, - 0x1fdd, 0x1fe0, + 0x1fd4, 0x1fd6, + 0x1fdc, 0x1fe0, 0x1fed, 0x1ff2, + 0x1ff5, 0x1ff6, 0x1ffd, 0x200e, 0x2010, 0x2071, - 0x2074, 0x207f, + 0x2072, 0x207f, 0x2080, 0x2090, - 0x20a0, 0x2102, + 0x209d, 0x2102, 0x2103, 0x2107, 0x2108, 0x210a, 0x2114, 0x2115, @@ -801,35 +978,59 @@ public final class NumericShaper implements java.io.Serializable { 0x24ea, 0x26ac, 0x26ad, 0x2800, 0x2900, 0x2c00, + 0x2c2f, 0x2c30, + 0x2c5f, 0x2c60, 0x2ce5, 0x2ceb, 0x2cef, 0x2cf2, - 0x2cf9, 0x2d00, - 0x2d7f, 0x2d80, - 0x2de0, 0x3005, + 0x2cf4, 0x2d00, + 0x2d26, 0x2d27, + 0x2d28, 0x2d2d, + 0x2d2e, 0x2d30, + 0x2d68, 0x2d6f, + 0x2d71, 0x2d80, + 0x2d97, 0x2da0, + 0x2da7, 0x2da8, + 0x2daf, 0x2db0, + 0x2db7, 0x2db8, + 0x2dbf, 0x2dc0, + 0x2dc7, 0x2dc8, + 0x2dcf, 0x2dd0, + 0x2dd7, 0x2dd8, + 0x2ddf, 0x3005, 0x3008, 0x3021, - 0x302a, 0x3031, + 0x302a, 0x302e, + 0x3030, 0x3031, 0x3036, 0x3038, 0x303d, 0x3041, - 0x3099, 0x309d, + 0x3097, 0x309d, 0x30a0, 0x30a1, 0x30fb, 0x30fc, - 0x31c0, 0x31f0, + 0x3100, 0x3105, + 0x312e, 0x3131, + 0x318f, 0x3190, + 0x31bb, 0x31f0, 0x321d, 0x3220, 0x3250, 0x3260, 0x327c, 0x327f, 0x32b1, 0x32c0, 0x32cc, 0x32d0, + 0x32ff, 0x3300, 0x3377, 0x337b, 0x33de, 0x33e0, 0x33ff, 0x3400, - 0x4dc0, 0x4e00, - 0xa490, 0xa4d0, + 0x4db6, 0x4e00, + 0x9fcd, 0xa000, + 0xa48d, 0xa4d0, 0xa60d, 0xa610, + 0xa62c, 0xa640, 0xa66f, 0xa680, - 0xa69f, 0xa6a0, + 0xa69e, 0xa6a0, 0xa6f0, 0xa6f2, - 0xa700, 0xa722, + 0xa6f8, 0xa722, 0xa788, 0xa789, + 0xa78f, 0xa790, + 0xa7ae, 0xa7b0, + 0xa7b2, 0xa7f7, 0xa802, 0xa803, 0xa806, 0xa807, 0xa80b, 0xa80c, @@ -838,77 +1039,241 @@ public final class NumericShaper implements java.io.Serializable { 0xa838, 0xa840, 0xa874, 0xa880, 0xa8c4, 0xa8ce, - 0xa8e0, 0xa8f2, + 0xa8da, 0xa8f2, + 0xa8fc, 0xa900, 0xa926, 0xa92e, 0xa947, 0xa952, - 0xa980, 0xa983, + 0xa954, 0xa95f, + 0xa97d, 0xa983, 0xa9b3, 0xa9b4, 0xa9b6, 0xa9ba, 0xa9bc, 0xa9bd, + 0xa9ce, 0xa9cf, + 0xa9da, 0xa9de, + 0xa9e5, 0xa9e6, + 0xa9ff, 0xaa00, 0xaa29, 0xaa2f, 0xaa31, 0xaa33, 0xaa35, 0xaa40, 0xaa43, 0xaa44, 0xaa4c, 0xaa4d, + 0xaa4e, 0xaa50, + 0xaa5a, 0xaa5c, + 0xaa7c, 0xaa7d, 0xaab0, 0xaab1, 0xaab2, 0xaab5, 0xaab7, 0xaab9, 0xaabe, 0xaac0, 0xaac1, 0xaac2, + 0xaac3, 0xaadb, 0xaaec, 0xaaee, 0xaaf6, 0xab01, + 0xab07, 0xab09, + 0xab0f, 0xab11, + 0xab17, 0xab20, + 0xab27, 0xab28, + 0xab2f, 0xab30, + 0xab60, 0xab64, + 0xab66, 0xabc0, 0xabe5, 0xabe6, 0xabe8, 0xabe9, 0xabed, 0xabf0, + 0xabfa, 0xac00, + 0xd7a4, 0xd7b0, + 0xd7c7, 0xd7cb, + 0xd7fc, 0xe000, + 0xfa6e, 0xfa70, + 0xfada, 0xfb00, + 0xfb07, 0xfb13, + 0xfb18, 0xfb1d, 0xfb1e, 0xfb1f, 0xfb29, 0xfb2a, - 0xfd3e, 0xfd50, - 0xfdfd, 0xfe70, + 0xfd3e, 0xfd40, + 0xfdd0, 0xfdf0, + 0xfdfd, 0xfdfe, + 0xfe00, 0xfe70, 0xfeff, 0xff21, 0xff3b, 0xff41, 0xff5b, 0xff66, - 0xffe0, 0x10000, + 0xffbf, 0xffc2, + 0xffc8, 0xffca, + 0xffd0, 0xffd2, + 0xffd8, 0xffda, + 0xffdd, 0x10000, + 0x1000c, 0x1000d, + 0x10027, 0x10028, + 0x1003b, 0x1003c, + 0x1003e, 0x1003f, + 0x1004e, 0x10050, + 0x1005e, 0x10080, + 0x100fb, 0x10100, 0x10101, 0x10102, + 0x10103, 0x10107, + 0x10134, 0x10137, 0x10140, 0x101d0, 0x101fd, 0x10280, + 0x1029d, 0x102a0, + 0x102d1, 0x10300, + 0x10324, 0x10330, + 0x1034b, 0x10350, + 0x10376, 0x10380, + 0x1039e, 0x1039f, + 0x103c4, 0x103c8, + 0x103d6, 0x10400, + 0x1049e, 0x104a0, + 0x104aa, 0x10500, + 0x10528, 0x10530, + 0x10564, 0x1056f, + 0x10570, 0x10600, + 0x10737, 0x10740, + 0x10756, 0x10760, + 0x10768, 0x10800, 0x1091f, 0x10920, - 0x10a01, 0x10a10, - 0x10a38, 0x10a40, + 0x10a01, 0x10a04, + 0x10a05, 0x10a07, + 0x10a0c, 0x10a10, + 0x10a38, 0x10a3b, + 0x10a3f, 0x10a40, + 0x10ae5, 0x10ae7, 0x10b39, 0x10b40, - 0x10e60, 0x11000, + 0x10e60, 0x10e7f, 0x11001, 0x11002, 0x11038, 0x11047, - 0x11052, 0x11066, - 0x11080, 0x11082, + 0x1104e, 0x11066, + 0x11070, 0x11082, 0x110b3, 0x110b7, 0x110b9, 0x110bb, - 0x11100, 0x11103, + 0x110c2, 0x110d0, + 0x110e9, 0x110f0, + 0x110fa, 0x11103, 0x11127, 0x1112c, 0x1112d, 0x11136, - 0x11180, 0x11182, + 0x11144, 0x11150, + 0x11173, 0x11174, + 0x11177, 0x11182, 0x111b6, 0x111bf, + 0x111c9, 0x111cd, + 0x111ce, 0x111d0, + 0x111db, 0x111e1, + 0x111f5, 0x11200, + 0x11212, 0x11213, + 0x1122f, 0x11232, + 0x11234, 0x11235, + 0x11236, 0x11238, + 0x1123e, 0x112b0, + 0x112df, 0x112e0, + 0x112e3, 0x112f0, + 0x112fa, 0x11302, + 0x11304, 0x11305, + 0x1130d, 0x1130f, + 0x11311, 0x11313, + 0x11329, 0x1132a, + 0x11331, 0x11332, + 0x11334, 0x11335, + 0x1133a, 0x1133d, + 0x11340, 0x11341, + 0x11345, 0x11347, + 0x11349, 0x1134b, + 0x1134e, 0x11357, + 0x11358, 0x1135d, + 0x11364, 0x11480, + 0x114b3, 0x114b9, + 0x114ba, 0x114bb, + 0x114bf, 0x114c1, + 0x114c2, 0x114c4, + 0x114c8, 0x114d0, + 0x114da, 0x11580, + 0x115b2, 0x115b8, + 0x115bc, 0x115be, + 0x115bf, 0x115c1, + 0x115ca, 0x11600, + 0x11633, 0x1163b, + 0x1163d, 0x1163e, + 0x1163f, 0x11641, + 0x11645, 0x11650, + 0x1165a, 0x11680, 0x116ab, 0x116ac, 0x116ad, 0x116ae, 0x116b0, 0x116b6, 0x116b7, 0x116c0, - 0x16f8f, 0x16f93, + 0x116ca, 0x118a0, + 0x118f3, 0x118ff, + 0x11900, 0x11ac0, + 0x11af9, 0x12000, + 0x12399, 0x12400, + 0x1246f, 0x12470, + 0x12475, 0x13000, + 0x1342f, 0x16800, + 0x16a39, 0x16a40, + 0x16a5f, 0x16a60, + 0x16a6a, 0x16a6e, + 0x16a70, 0x16ad0, + 0x16aee, 0x16af5, + 0x16af6, 0x16b00, + 0x16b30, 0x16b37, + 0x16b46, 0x16b50, + 0x16b5a, 0x16b5b, + 0x16b62, 0x16b63, + 0x16b78, 0x16b7d, + 0x16b90, 0x16f00, + 0x16f45, 0x16f50, + 0x16f7f, 0x16f93, + 0x16fa0, 0x1b000, + 0x1b002, 0x1bc00, + 0x1bc6b, 0x1bc70, + 0x1bc7d, 0x1bc80, + 0x1bc89, 0x1bc90, + 0x1bc9a, 0x1bc9c, + 0x1bc9d, 0x1bc9f, + 0x1bca0, 0x1d000, + 0x1d0f6, 0x1d100, + 0x1d127, 0x1d129, 0x1d167, 0x1d16a, 0x1d173, 0x1d183, 0x1d185, 0x1d18c, 0x1d1aa, 0x1d1ae, - 0x1d200, 0x1d360, + 0x1d1de, 0x1d360, + 0x1d372, 0x1d400, + 0x1d455, 0x1d456, + 0x1d49d, 0x1d49e, + 0x1d4a0, 0x1d4a2, + 0x1d4a3, 0x1d4a5, + 0x1d4a7, 0x1d4a9, + 0x1d4ad, 0x1d4ae, + 0x1d4ba, 0x1d4bb, + 0x1d4bc, 0x1d4bd, + 0x1d4c4, 0x1d4c5, + 0x1d506, 0x1d507, + 0x1d50b, 0x1d50d, + 0x1d515, 0x1d516, + 0x1d51d, 0x1d51e, + 0x1d53a, 0x1d53b, + 0x1d53f, 0x1d540, + 0x1d545, 0x1d546, + 0x1d547, 0x1d54a, + 0x1d551, 0x1d552, + 0x1d6a6, 0x1d6a8, 0x1d6db, 0x1d6dc, 0x1d715, 0x1d716, 0x1d74f, 0x1d750, 0x1d789, 0x1d78a, 0x1d7c3, 0x1d7c4, - 0x1d7ce, 0x1ee00, - 0x1eef0, 0x1f110, + 0x1d7cc, 0x1e800, + 0x1e8d0, 0x1e8d7, + 0x1eef0, 0x1eef2, + 0x1f000, 0x1f110, + 0x1f12f, 0x1f130, 0x1f16a, 0x1f170, - 0x1f300, 0x1f48c, - 0x1f48d, 0x1f524, - 0x1f525, 0x20000, - 0xe0001, 0xf0000, + 0x1f19b, 0x1f1e6, + 0x1f203, 0x1f210, + 0x1f23b, 0x1f240, + 0x1f249, 0x1f250, + 0x1f252, 0x20000, + 0x2a6d7, 0x2a700, + 0x2b735, 0x2b740, + 0x2b81e, 0x2f800, + 0x2fa1e, 0xf0000, + 0xffffe, 0x100000, 0x10fffe, 0x10ffff // sentinel }; diff --git a/jdk/test/java/awt/font/NumericShaper/ShapingTest.java b/jdk/test/java/awt/font/NumericShaper/ShapingTest.java index a82461f5a81..0c868ecf411 100644 --- a/jdk/test/java/awt/font/NumericShaper/ShapingTest.java +++ b/jdk/test/java/awt/font/NumericShaper/ShapingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 6842557 6943963 6959267 + * @bug 6842557 6943963 6959267 8032446 * @summary confirm that shaping works as expected. (Mainly for new characters which were added in Unicode 5 and 6) * used where appropriate. */ @@ -40,6 +40,7 @@ public class ShapingTest { test6842557(); test6943963(); test6903266(); + test8032446(); if (err) { throw new RuntimeException("shape() returned unexpected value."); @@ -138,6 +139,18 @@ public class ShapingTest { checkResult("Range.MEETEI_MAYEK", ns, given, expected); } + private static void test8032446() { + NumericShaper ns = getContextualShaper(EnumSet.of(Range.SINHALA)); + String given = "\u0d85 012"; + String expected = "\u0d85 \u0de6\u0de7\u0de8"; + checkResult("Range.SINHALA", ns, given, expected); + + ns = getContextualShaper(EnumSet.of(Range.MYANMAR_TAI_LAING)); + given = "\ua9e2 012"; + expected = "\ua9e2 \ua9f0\ua9f1\ua9f2"; + checkResult("Range.MYANMAR_TAI_LAING", ns, given, expected); + } + private static void checkResult(String ranges, NumericShaper ns, String given, String expected) { char[] text = given.toCharArray(); diff --git a/jdk/test/java/lang/Character/CheckProp.java b/jdk/test/java/lang/Character/CheckProp.java index c460d42ef78..e00eae37cc5 100644 --- a/jdk/test/java/lang/Character/CheckProp.java +++ b/jdk/test/java/lang/Character/CheckProp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * 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,7 +24,7 @@ /** * @test - * @bug 7037261 7070436 7198195 + * @bug 7037261 7070436 7198195 8032446 * @summary Check j.l.Character.isLowerCase/isUppercase/isAlphabetic/isIdeographic */ diff --git a/jdk/test/java/lang/Character/CheckScript.java b/jdk/test/java/lang/Character/CheckScript.java index 713e3c8e886..5a8b2794337 100644 --- a/jdk/test/java/lang/Character/CheckScript.java +++ b/jdk/test/java/lang/Character/CheckScript.java @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. * 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,7 +23,7 @@ /** * @test - * @bug 6945564 6959267 7033561 7070436 7198195 + * @bug 6945564 6959267 7033561 7070436 7198195 8032446 * @summary Check that the j.l.Character.UnicodeScript */ diff --git a/jdk/test/java/lang/Character/PropList.txt b/jdk/test/java/lang/Character/PropList.txt index 9ce7eec9713..82f650d5749 100644 --- a/jdk/test/java/lang/Character/PropList.txt +++ b/jdk/test/java/lang/Character/PropList.txt @@ -1,8 +1,8 @@ -# PropList-6.2.0.txt -# Date: 2012-05-23, 20:34:59 GMT [MD] +# PropList-7.0.0.txt +# Date: 2014-02-19, 15:51:26 GMT [MD] # # Unicode Character Database -# Copyright (c) 1991-2012 Unicode, Inc. +# Copyright (c) 1991-2014 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # For documentation, see http://www.unicode.org/reports/tr44/ @@ -13,7 +13,6 @@ 0085 ; White_Space # Cc <control-0085> 00A0 ; White_Space # Zs NO-BREAK SPACE 1680 ; White_Space # Zs OGHAM SPACE MARK -180E ; White_Space # Zs MONGOLIAN VOWEL SEPARATOR 2000..200A ; White_Space # Zs [11] EN QUAD..HAIR SPACE 2028 ; White_Space # Zl LINE SEPARATOR 2029 ; White_Space # Zp PARAGRAPH SEPARATOR @@ -21,14 +20,16 @@ 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE 3000 ; White_Space # Zs IDEOGRAPHIC SPACE -# Total code points: 26 +# Total code points: 25 # ================================================ +061C ; Bidi_Control # Cf ARABIC LETTER MARK 200E..200F ; Bidi_Control # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK 202A..202E ; Bidi_Control # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE +2066..2069 ; Bidi_Control # Cf [4] LEFT-TO-RIGHT ISOLATE..POP DIRECTIONAL ISOLATE -# Total code points: 7 +# Total code points: 12 # ================================================ @@ -51,6 +52,7 @@ 2E17 ; Dash # Pd DOUBLE OBLIQUE HYPHEN 2E1A ; Dash # Pd HYPHEN WITH DIAERESIS 2E3A..2E3B ; Dash # Pd [2] TWO-EM DASH..THREE-EM DASH +2E40 ; Dash # Pd DOUBLE HYPHEN 301C ; Dash # Pd WAVE DASH 3030 ; Dash # Pd WAVY DASH 30A0 ; Dash # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN @@ -59,7 +61,7 @@ FE58 ; Dash # Pd SMALL EM DASH FE63 ; Dash # Pd SMALL HYPHEN-MINUS FF0D ; Dash # Pd FULLWIDTH HYPHEN-MINUS -# Total code points: 27 +# Total code points: 28 # ================================================ @@ -91,6 +93,7 @@ FF65 ; Hyphen # Po HALFWIDTH KATAKANA MIDDLE DOT 201F ; Quotation_Mark # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK 2039 ; Quotation_Mark # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK 203A ; Quotation_Mark # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +2E42 ; Quotation_Mark # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK 300C ; Quotation_Mark # Ps LEFT CORNER BRACKET 300D ; Quotation_Mark # Pe RIGHT CORNER BRACKET 300E ; Quotation_Mark # Ps LEFT WHITE CORNER BRACKET @@ -106,7 +109,7 @@ FF07 ; Quotation_Mark # Po FULLWIDTH APOSTROPHE FF62 ; Quotation_Mark # Ps HALFWIDTH LEFT CORNER BRACKET FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET -# Total code points: 29 +# Total code points: 30 # ================================================ @@ -136,6 +139,7 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET 1361..1368 ; Terminal_Punctuation # Po [8] ETHIOPIC WORDSPACE..ETHIOPIC PARAGRAPH SEPARATOR 166D..166E ; Terminal_Punctuation # Po [2] CANADIAN SYLLABICS CHI SIGN..CANADIAN SYLLABICS FULL STOP 16EB..16ED ; Terminal_Punctuation # Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION +1735..1736 ; Terminal_Punctuation # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION 17D4..17D6 ; Terminal_Punctuation # Po [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH 17DA ; Terminal_Punctuation # Po KHMER SIGN KOOMUUT 1802..1805 ; Terminal_Punctuation # Po [4] MONGOLIAN COMMA..MONGOLIAN FOUR DOTS @@ -149,6 +153,8 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET 203C..203D ; Terminal_Punctuation # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG 2047..2049 ; Terminal_Punctuation # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK 2E2E ; Terminal_Punctuation # Po REVERSED QUESTION MARK +2E3C ; Terminal_Punctuation # Po STENOGRAPHIC FULL STOP +2E41 ; Terminal_Punctuation # Po REVERSED COMMA 3001..3002 ; Terminal_Punctuation # Po [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP A4FE..A4FF ; Terminal_Punctuation # Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP A60D..A60F ; Terminal_Punctuation # Po [3] VAI COMMA..VAI QUESTION MARK @@ -174,14 +180,27 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA 103D0 ; Terminal_Punctuation # Po OLD PERSIAN WORD DIVIDER 10857 ; Terminal_Punctuation # Po IMPERIAL ARAMAIC SECTION SIGN 1091F ; Terminal_Punctuation # Po PHOENICIAN WORD SEPARATOR +10A56..10A57 ; Terminal_Punctuation # Po [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA +10AF0..10AF5 ; Terminal_Punctuation # Po [6] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION TWO DOTS 10B3A..10B3F ; Terminal_Punctuation # Po [6] TINY TWO DOTS OVER ONE DOT PUNCTUATION..LARGE ONE RING OVER TWO RINGS PUNCTUATION +10B99..10B9C ; Terminal_Punctuation # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT 11047..1104D ; Terminal_Punctuation # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS 110BE..110C1 ; Terminal_Punctuation # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA 11141..11143 ; Terminal_Punctuation # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK 111C5..111C6 ; Terminal_Punctuation # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA -12470..12473 ; Terminal_Punctuation # Po [4] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON +111CD ; Terminal_Punctuation # Po SHARADA SUTRA MARK +11238..1123C ; Terminal_Punctuation # Po [5] KHOJKI DANDA..KHOJKI DOUBLE SECTION MARK +115C2..115C5 ; Terminal_Punctuation # Po [4] SIDDHAM DANDA..SIDDHAM SEPARATOR BAR +115C9 ; Terminal_Punctuation # Po SIDDHAM END OF TEXT MARK +11641..11642 ; Terminal_Punctuation # Po [2] MODI DANDA..MODI DOUBLE DANDA +12470..12474 ; Terminal_Punctuation # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON +16A6E..16A6F ; Terminal_Punctuation # Po [2] MRO DANDA..MRO DOUBLE DANDA +16AF5 ; Terminal_Punctuation # Po BASSA VAH FULL STOP +16B37..16B39 ; Terminal_Punctuation # Po [3] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN CIM CHEEM +16B44 ; Terminal_Punctuation # Po PAHAWH HMONG SIGN XAUS +1BC9F ; Terminal_Punctuation # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP -# Total code points: 176 +# Total code points: 214 # ================================================ @@ -230,6 +249,10 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA 21D5..21DB ; Other_Math # So [7] UP DOWN DOUBLE ARROW..RIGHTWARDS TRIPLE ARROW 21DD ; Other_Math # So RIGHTWARDS SQUIGGLE ARROW 21E4..21E5 ; Other_Math # So [2] LEFTWARDS ARROW TO BAR..RIGHTWARDS ARROW TO BAR +2308 ; Other_Math # Ps LEFT CEILING +2309 ; Other_Math # Pe RIGHT CEILING +230A ; Other_Math # Ps LEFT FLOOR +230B ; Other_Math # Pe RIGHT FLOOR 23B4..23B5 ; Other_Math # So [2] TOP SQUARE BRACKET..BOTTOM SQUARE BRACKET 23B7 ; Other_Math # So RADICAL SYMBOL BOTTOM 23D0 ; Other_Math # So VERTICAL LINE EXTENSION @@ -358,7 +381,7 @@ FF3E ; Other_Math # Sk FULLWIDTH CIRCUMFLEX ACCENT 1EEA5..1EEA9 ; Other_Math # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH 1EEAB..1EEBB ; Other_Math # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN -# Total code points: 1358 +# Total code points: 1362 # ================================================ @@ -403,8 +426,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0825..0827 ; Other_Alphabetic # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082C ; Other_Alphabetic # Mn [4] SAMARITAN VOWEL SIGN LONG I..SAMARITAN VOWEL SIGN SUKUN 08E4..08E9 ; Other_Alphabetic # Mn [6] ARABIC CURLY FATHA..ARABIC CURLY KASRATAN -08F0..08FE ; Other_Alphabetic # Mn [15] ARABIC OPEN FATHATAN..ARABIC DAMMA WITH DOT -0900..0902 ; Other_Alphabetic # Mn [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA +08F0..0902 ; Other_Alphabetic # Mn [19] ARABIC OPEN FATHATAN..DEVANAGARI SIGN ANUSVARA 0903 ; Other_Alphabetic # Mc DEVANAGARI SIGN VISARGA 093A ; Other_Alphabetic # Mn DEVANAGARI VOWEL SIGN OE 093B ; Other_Alphabetic # Mc DEVANAGARI VOWEL SIGN OOE @@ -457,6 +479,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0BC6..0BC8 ; Other_Alphabetic # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI 0BCA..0BCC ; Other_Alphabetic # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU 0BD7 ; Other_Alphabetic # Mc TAMIL AU LENGTH MARK +0C00 ; Other_Alphabetic # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE 0C01..0C03 ; Other_Alphabetic # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA 0C3E..0C40 ; Other_Alphabetic # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II 0C41..0C44 ; Other_Alphabetic # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR @@ -464,6 +487,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0C4A..0C4C ; Other_Alphabetic # Mn [3] TELUGU VOWEL SIGN O..TELUGU VOWEL SIGN AU 0C55..0C56 ; Other_Alphabetic # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK 0C62..0C63 ; Other_Alphabetic # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL +0C81 ; Other_Alphabetic # Mn KANNADA SIGN CANDRABINDU 0C82..0C83 ; Other_Alphabetic # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 0CBE ; Other_Alphabetic # Mc KANNADA VOWEL SIGN AA 0CBF ; Other_Alphabetic # Mn KANNADA VOWEL SIGN I @@ -474,6 +498,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0CCC ; Other_Alphabetic # Mn KANNADA VOWEL SIGN AU 0CD5..0CD6 ; Other_Alphabetic # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK 0CE2..0CE3 ; Other_Alphabetic # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL +0D01 ; Other_Alphabetic # Mn MALAYALAM SIGN CANDRABINDU 0D02..0D03 ; Other_Alphabetic # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D3E..0D40 ; Other_Alphabetic # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II 0D41..0D44 ; Other_Alphabetic # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR @@ -538,7 +563,8 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 19B0..19C0 ; Other_Alphabetic # Mc [17] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE VOWEL SIGN IY 19C8..19C9 ; Other_Alphabetic # Mc [2] NEW TAI LUE TONE MARK-1..NEW TAI LUE TONE MARK-2 1A17..1A18 ; Other_Alphabetic # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U -1A19..1A1B ; Other_Alphabetic # Mc [3] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN AE +1A19..1A1A ; Other_Alphabetic # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O +1A1B ; Other_Alphabetic # Mn BUGINESE VOWEL SIGN AE 1A55 ; Other_Alphabetic # Mc TAI THAM CONSONANT SIGN MEDIAL RA 1A56 ; Other_Alphabetic # Mn TAI THAM CONSONANT SIGN MEDIAL LA 1A57 ; Other_Alphabetic # Mc TAI THAM CONSONANT SIGN LA TANG LAI @@ -564,7 +590,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 1BA2..1BA5 ; Other_Alphabetic # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU 1BA6..1BA7 ; Other_Alphabetic # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG 1BA8..1BA9 ; Other_Alphabetic # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG -1BAC..1BAD ; Other_Alphabetic # Mc [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA +1BAC..1BAD ; Other_Alphabetic # Mn [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA 1BE7 ; Other_Alphabetic # Mc BATAK VOWEL SIGN E 1BE8..1BE9 ; Other_Alphabetic # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE 1BEA..1BEC ; Other_Alphabetic # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O @@ -575,6 +601,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 1C2C..1C33 ; Other_Alphabetic # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T 1C34..1C35 ; Other_Alphabetic # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG 1CF2..1CF3 ; Other_Alphabetic # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA +1DE7..1DF4 ; Other_Alphabetic # Mn [14] COMBINING LATIN SMALL LETTER ALPHA..COMBINING LATIN SMALL LETTER U WITH DIAERESIS 24B6..24E9 ; Other_Alphabetic # So [52] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN SMALL LETTER Z 2DE0..2DFF ; Other_Alphabetic # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS A674..A67B ; Other_Alphabetic # Mn [8] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC LETTER OMEGA @@ -616,6 +643,7 @@ ABE6..ABE7 ; Other_Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETE ABE8 ; Other_Alphabetic # Mn MEETEI MAYEK VOWEL SIGN UNAP ABE9..ABEA ; Other_Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA +10376..1037A ; Other_Alphabetic # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII 10A01..10A03 ; Other_Alphabetic # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R 10A05..10A06 ; Other_Alphabetic # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O 10A0C..10A0F ; Other_Alphabetic # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA @@ -636,14 +664,54 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 111B3..111B5 ; Other_Alphabetic # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II 111B6..111BE ; Other_Alphabetic # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O 111BF ; Other_Alphabetic # Mc SHARADA VOWEL SIGN AU +1122C..1122E ; Other_Alphabetic # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II +1122F..11231 ; Other_Alphabetic # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI +11232..11233 ; Other_Alphabetic # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU +11234 ; Other_Alphabetic # Mn KHOJKI SIGN ANUSVARA +11237 ; Other_Alphabetic # Mn KHOJKI SIGN SHADDA +112DF ; Other_Alphabetic # Mn KHUDAWADI SIGN ANUSVARA +112E0..112E2 ; Other_Alphabetic # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II +112E3..112E8 ; Other_Alphabetic # Mn [6] KHUDAWADI VOWEL SIGN U..KHUDAWADI VOWEL SIGN AU +11301 ; Other_Alphabetic # Mn GRANTHA SIGN CANDRABINDU +11302..11303 ; Other_Alphabetic # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA +1133E..1133F ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I +11340 ; Other_Alphabetic # Mn GRANTHA VOWEL SIGN II +11341..11344 ; Other_Alphabetic # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR +11347..11348 ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI +1134B..1134C ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN OO..GRANTHA VOWEL SIGN AU +11357 ; Other_Alphabetic # Mc GRANTHA AU LENGTH MARK +11362..11363 ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +114B0..114B2 ; Other_Alphabetic # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II +114B3..114B8 ; Other_Alphabetic # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL +114B9 ; Other_Alphabetic # Mc TIRHUTA VOWEL SIGN E +114BA ; Other_Alphabetic # Mn TIRHUTA VOWEL SIGN SHORT E +114BB..114BE ; Other_Alphabetic # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU +114BF..114C0 ; Other_Alphabetic # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA +114C1 ; Other_Alphabetic # Mc TIRHUTA SIGN VISARGA +115AF..115B1 ; Other_Alphabetic # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II +115B2..115B5 ; Other_Alphabetic # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR +115B8..115BB ; Other_Alphabetic # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU +115BC..115BD ; Other_Alphabetic # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA +115BE ; Other_Alphabetic # Mc SIDDHAM SIGN VISARGA +11630..11632 ; Other_Alphabetic # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II +11633..1163A ; Other_Alphabetic # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI +1163B..1163C ; Other_Alphabetic # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU +1163D ; Other_Alphabetic # Mn MODI SIGN ANUSVARA +1163E ; Other_Alphabetic # Mc MODI SIGN VISARGA +11640 ; Other_Alphabetic # Mn MODI SIGN ARDHACANDRA 116AB ; Other_Alphabetic # Mn TAKRI SIGN ANUSVARA 116AC ; Other_Alphabetic # Mc TAKRI SIGN VISARGA 116AD ; Other_Alphabetic # Mn TAKRI VOWEL SIGN AA 116AE..116AF ; Other_Alphabetic # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II 116B0..116B5 ; Other_Alphabetic # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU +16B30..16B36 ; Other_Alphabetic # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F51..16F7E ; Other_Alphabetic # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG +1BC9E ; Other_Alphabetic # Mn DUPLOYAN DOUBLE MARK +1F130..1F149 ; Other_Alphabetic # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z +1F150..1F169 ; Other_Alphabetic # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z +1F170..1F189 ; Other_Alphabetic # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 922 +# Total code points: 1116 # ================================================ @@ -746,6 +814,7 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 1939..193B ; Diacritic # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I 1A75..1A7C ; Diacritic # Mn [8] TAI THAM SIGN TONE-1..TAI THAM SIGN KHUEN-LUE KARAN 1A7F ; Diacritic # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT +1AB0..1ABD ; Diacritic # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW 1B34 ; Diacritic # Mn BALINESE SIGN REREKAN 1B44 ; Diacritic # Mc BALINESE ADEG ADEG 1B6B..1B73 ; Diacritic # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG @@ -760,8 +829,10 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 1CE2..1CE8 ; Diacritic # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL 1CED ; Diacritic # Mn VEDIC SIGN TIRYAK 1CF4 ; Diacritic # Mn VEDIC TONE CANDRA ABOVE +1CF8..1CF9 ; Diacritic # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE 1D2C..1D6A ; Diacritic # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI 1DC4..1DCF ; Diacritic # Mn [12] COMBINING MACRON-ACUTE..COMBINING ZIGZAG BELOW +1DF5 ; Diacritic # Mn COMBINING UP TACK ABOVE 1DFD..1DFF ; Diacritic # Mn [3] COMBINING ALMOST EQUAL TO BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 1FBD ; Diacritic # Sk GREEK KORONIS 1FBF..1FC1 ; Diacritic # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI @@ -779,6 +850,7 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM A66F ; Diacritic # Mn COMBINING CYRILLIC VZMET A67C..A67D ; Diacritic # Mn [2] COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK A67F ; Diacritic # Lm CYRILLIC PAYEROK +A69C..A69D ; Diacritic # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN A6F0..A6F1 ; Diacritic # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS A717..A71F ; Diacritic # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK A720..A721 ; Diacritic # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE @@ -791,26 +863,45 @@ A92E ; Diacritic # Po KAYAH LI SIGN CWI A953 ; Diacritic # Mc REJANG VIRAMA A9B3 ; Diacritic # Mn JAVANESE SIGN CECAK TELU A9C0 ; Diacritic # Mc JAVANESE PANGKON +A9E5 ; Diacritic # Mn MYANMAR SIGN SHAN SAW AA7B ; Diacritic # Mc MYANMAR SIGN PAO KAREN TONE +AA7C ; Diacritic # Mn MYANMAR SIGN TAI LAING TONE-2 +AA7D ; Diacritic # Mc MYANMAR SIGN TAI LAING TONE-5 AABF ; Diacritic # Mn TAI VIET TONE MAI EK AAC0 ; Diacritic # Lo TAI VIET TONE MAI NUENG AAC1 ; Diacritic # Mn TAI VIET TONE MAI THO AAC2 ; Diacritic # Lo TAI VIET TONE MAI SONG AAF6 ; Diacritic # Mn MEETEI MAYEK VIRAMA +AB5B ; Diacritic # Sk MODIFIER BREVE WITH INVERTED BREVE +AB5C..AB5F ; Diacritic # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK ABEC ; Diacritic # Mc MEETEI MAYEK LUM IYEK ABED ; Diacritic # Mn MEETEI MAYEK APUN IYEK FB1E ; Diacritic # Mn HEBREW POINT JUDEO-SPANISH VARIKA -FE20..FE26 ; Diacritic # Mn [7] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON +FE20..FE2D ; Diacritic # Mn [14] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON BELOW FF3E ; Diacritic # Sk FULLWIDTH CIRCUMFLEX ACCENT FF40 ; Diacritic # Sk FULLWIDTH GRAVE ACCENT FF70 ; Diacritic # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK FF9E..FF9F ; Diacritic # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK FFE3 ; Diacritic # Sk FULLWIDTH MACRON +102E0 ; Diacritic # Mn COPTIC EPACT THOUSANDS MARK +10AE5..10AE6 ; Diacritic # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW 110B9..110BA ; Diacritic # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA 11133..11134 ; Diacritic # Mn [2] CHAKMA VIRAMA..CHAKMA MAAYYAA +11173 ; Diacritic # Mn MAHAJANI SIGN NUKTA 111C0 ; Diacritic # Mc SHARADA SIGN VIRAMA +11235 ; Diacritic # Mc KHOJKI SIGN VIRAMA +11236 ; Diacritic # Mn KHOJKI SIGN NUKTA +112E9..112EA ; Diacritic # Mn [2] KHUDAWADI SIGN NUKTA..KHUDAWADI SIGN VIRAMA +1133C ; Diacritic # Mn GRANTHA SIGN NUKTA +1134D ; Diacritic # Mc GRANTHA SIGN VIRAMA +11366..1136C ; Diacritic # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX +11370..11374 ; Diacritic # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +114C2..114C3 ; Diacritic # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA +115BF..115C0 ; Diacritic # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA +1163F ; Diacritic # Mn MODI SIGN VIRAMA 116B6 ; Diacritic # Mc TAKRI SIGN VIRAMA 116B7 ; Diacritic # Mn TAKRI SIGN NUKTA +16AF0..16AF4 ; Diacritic # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16F8F..16F92 ; Diacritic # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16F93..16F9F ; Diacritic # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 1D167..1D169 ; Diacritic # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 @@ -818,8 +909,9 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON 1D17B..1D182 ; Diacritic # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE 1D185..1D18B ; Diacritic # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE 1D1AA..1D1AD ; Diacritic # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO +1E8D0..1E8D6 ; Diacritic # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS -# Total code points: 693 +# Total code points: 766 # ================================================ @@ -841,12 +933,16 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON A015 ; Extender # Lm YI SYLLABLE WU A60C ; Extender # Lm VAI SYLLABLE LENGTHENER A9CF ; Extender # Lm JAVANESE PANGRANGKEP +A9E6 ; Extender # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION AA70 ; Extender # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION AADD ; Extender # Lm TAI VIET SYMBOL SAM AAF3..AAF4 ; Extender # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +1135D ; Extender # Lo GRANTHA SIGN PLUTA +115C6..115C8 ; Extender # Po [3] SIDDHAM REPETITION MARK-1..SIDDHAM REPETITION MARK-3 +16B42..16B43 ; Extender # Lm [2] PAHAWH HMONG SIGN VOS NRUA..PAHAWH HMONG SIGN IB YAM -# Total code points: 31 +# Total code points: 38 # ================================================ @@ -866,17 +962,22 @@ FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND 2170..217F ; Other_Lowercase # Nl [16] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL ONE THOUSAND 24D0..24E9 ; Other_Lowercase # So [26] CIRCLED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z 2C7C..2C7D ; Other_Lowercase # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V +A69C..A69D ; Other_Lowercase # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN A770 ; Other_Lowercase # Lm MODIFIER LETTER US A7F8..A7F9 ; Other_Lowercase # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE +AB5C..AB5F ; Other_Lowercase # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK -# Total code points: 183 +# Total code points: 189 # ================================================ 2160..216F ; Other_Uppercase # Nl [16] ROMAN NUMERAL ONE..ROMAN NUMERAL ONE THOUSAND 24B6..24CF ; Other_Uppercase # So [26] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN CAPITAL LETTER Z +1F130..1F149 ; Other_Uppercase # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z +1F150..1F169 ; Other_Uppercase # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z +1F170..1F189 ; Other_Uppercase # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 42 +# Total code points: 120 # ================================================ @@ -918,10 +1019,15 @@ FFFFE..FFFFF ; Noncharacter_Code_Point # Cn [2] <noncharacter-FFFFE>..<noncha 200C..200D ; Other_Grapheme_Extend # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER 302E..302F ; Other_Grapheme_Extend # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK +1133E ; Other_Grapheme_Extend # Mc GRANTHA VOWEL SIGN AA +11357 ; Other_Grapheme_Extend # Mc GRANTHA AU LENGTH MARK +114B0 ; Other_Grapheme_Extend # Mc TIRHUTA VOWEL SIGN AA +114BD ; Other_Grapheme_Extend # Mc TIRHUTA VOWEL SIGN SHORT O +115AF ; Other_Grapheme_Extend # Mc SIDDHAM VOWEL SIGN AA 1D165 ; Other_Grapheme_Extend # Mc MUSICAL SYMBOL COMBINING STEM 1D16E..1D172 ; Other_Grapheme_Extend # Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5 -# Total code points: 25 +# Total code points: 30 # ================================================ @@ -966,7 +1072,7 @@ FA27..FA29 ; Unified_Ideograph # Lo [3] CJK COMPATIBILITY IDEOGRAPH-FA27..C 034F ; Other_Default_Ignorable_Code_Point # Mn COMBINING GRAPHEME JOINER 115F..1160 ; Other_Default_Ignorable_Code_Point # Lo [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER 17B4..17B5 ; Other_Default_Ignorable_Code_Point # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA -2065..2069 ; Other_Default_Ignorable_Code_Point # Cn [5] <reserved-2065>..<reserved-2069> +2065 ; Other_Default_Ignorable_Code_Point # Cn <reserved-2065> 3164 ; Other_Default_Ignorable_Code_Point # Lo HANGUL FILLER FFA0 ; Other_Default_Ignorable_Code_Point # Lo HALFWIDTH HANGUL FILLER FFF0..FFF8 ; Other_Default_Ignorable_Code_Point # Cn [9] <reserved-FFF0>..<reserved-FFF8> @@ -975,7 +1081,7 @@ E0002..E001F ; Other_Default_Ignorable_Code_Point # Cn [30] <reserved-E0002>.. E0080..E00FF ; Other_Default_Ignorable_Code_Point # Cn [128] <reserved-E0080>..<reserved-E00FF> E01F0..E0FFF ; Other_Default_Ignorable_Code_Point # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> -# Total code points: 3780 +# Total code points: 3776 # ================================================ @@ -1060,8 +1166,6 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET 0021 ; STerm # Po EXCLAMATION MARK 002E ; STerm # Po FULL STOP 003F ; STerm # Po QUESTION MARK -055C ; STerm # Po ARMENIAN EXCLAMATION MARK -055E ; STerm # Po ARMENIAN QUESTION MARK 0589 ; STerm # Po ARMENIAN FULL STOP 061F ; STerm # Po ARABIC QUESTION MARK 06D4 ; STerm # Po ARABIC FULL STOP @@ -1084,6 +1188,7 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET 203C..203D ; STerm # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG 2047..2049 ; STerm # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK 2E2E ; STerm # Po REVERSED QUESTION MARK +2E3C ; STerm # Po STENOGRAPHIC FULL STOP 3002 ; STerm # Po IDEOGRAPHIC FULL STOP A4FF ; STerm # Po LISU PUNCTUATION FULL STOP A60E..A60F ; STerm # Po [2] VAI FULL STOP..VAI QUESTION MARK @@ -1107,8 +1212,19 @@ FF61 ; STerm # Po HALFWIDTH IDEOGRAPHIC FULL STOP 110BE..110C1 ; STerm # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA 11141..11143 ; STerm # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK 111C5..111C6 ; STerm # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA +111CD ; STerm # Po SHARADA SUTRA MARK +11238..11239 ; STerm # Po [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA +1123B..1123C ; STerm # Po [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK +115C2..115C3 ; STerm # Po [2] SIDDHAM DANDA..SIDDHAM DOUBLE DANDA +115C9 ; STerm # Po SIDDHAM END OF TEXT MARK +11641..11642 ; STerm # Po [2] MODI DANDA..MODI DOUBLE DANDA +16A6E..16A6F ; STerm # Po [2] MRO DANDA..MRO DOUBLE DANDA +16AF5 ; STerm # Po BASSA VAH FULL STOP +16B37..16B38 ; STerm # Po [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB +16B44 ; STerm # Po PAHAWH HMONG SIGN XAUS +1BC9F ; STerm # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP -# Total code points: 83 +# Total code points: 99 # ================================================ @@ -1210,7 +1326,10 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 21D5..21F3 ; Pattern_Syntax # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW 21F4..22FF ; Pattern_Syntax # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP 2300..2307 ; Pattern_Syntax # So [8] DIAMETER SIGN..WAVY LINE -2308..230B ; Pattern_Syntax # Sm [4] LEFT CEILING..RIGHT FLOOR +2308 ; Pattern_Syntax # Ps LEFT CEILING +2309 ; Pattern_Syntax # Pe RIGHT CEILING +230A ; Pattern_Syntax # Ps LEFT FLOOR +230B ; Pattern_Syntax # Pe RIGHT FLOOR 230C..231F ; Pattern_Syntax # So [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER 2320..2321 ; Pattern_Syntax # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL 2322..2328 ; Pattern_Syntax # So [7] FROWN..KEYBOARD @@ -1222,8 +1341,8 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 239B..23B3 ; Pattern_Syntax # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM 23B4..23DB ; Pattern_Syntax # So [40] TOP SQUARE BRACKET..FUSE 23DC..23E1 ; Pattern_Syntax # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET -23E2..23F3 ; Pattern_Syntax # So [18] WHITE TRAPEZIUM..HOURGLASS WITH FLOWING SAND -23F4..23FF ; Pattern_Syntax # Cn [12] <reserved-23F4>..<reserved-23FF> +23E2..23FA ; Pattern_Syntax # So [25] WHITE TRAPEZIUM..BLACK CIRCLE FOR RECORD +23FB..23FF ; Pattern_Syntax # Cn [5] <reserved-23FB>..<reserved-23FF> 2400..2426 ; Pattern_Syntax # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO 2427..243F ; Pattern_Syntax # Cn [25] <reserved-2427>..<reserved-243F> 2440..244A ; Pattern_Syntax # So [11] OCR HOOK..OCR DOUBLE BACKSLASH @@ -1236,9 +1355,7 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 25F8..25FF ; Pattern_Syntax # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE 2600..266E ; Pattern_Syntax # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN 266F ; Pattern_Syntax # Sm MUSIC SHARP SIGN -2670..26FF ; Pattern_Syntax # So [144] WEST SYRIAC CROSS..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE -2700 ; Pattern_Syntax # Cn <reserved-2700> -2701..2767 ; Pattern_Syntax # So [103] UPPER BLADE SCISSORS..ROTATED FLORAL HEART BULLET +2670..2767 ; Pattern_Syntax # So [248] WEST SYRIAC CROSS..ROTATED FLORAL HEART BULLET 2768 ; Pattern_Syntax # Ps MEDIUM LEFT PARENTHESIS ORNAMENT 2769 ; Pattern_Syntax # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT 276A ; Pattern_Syntax # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT @@ -1306,9 +1423,16 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 2B30..2B44 ; Pattern_Syntax # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET 2B45..2B46 ; Pattern_Syntax # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW 2B47..2B4C ; Pattern_Syntax # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR -2B4D..2B4F ; Pattern_Syntax # Cn [3] <reserved-2B4D>..<reserved-2B4F> -2B50..2B59 ; Pattern_Syntax # So [10] WHITE MEDIUM STAR..HEAVY CIRCLED SALTIRE -2B5A..2BFF ; Pattern_Syntax # Cn [166] <reserved-2B5A>..<reserved-2BFF> +2B4D..2B73 ; Pattern_Syntax # So [39] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR +2B74..2B75 ; Pattern_Syntax # Cn [2] <reserved-2B74>..<reserved-2B75> +2B76..2B95 ; Pattern_Syntax # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW +2B96..2B97 ; Pattern_Syntax # Cn [2] <reserved-2B96>..<reserved-2B97> +2B98..2BB9 ; Pattern_Syntax # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX +2BBA..2BBC ; Pattern_Syntax # Cn [3] <reserved-2BBA>..<reserved-2BBC> +2BBD..2BC8 ; Pattern_Syntax # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED +2BC9 ; Pattern_Syntax # Cn <reserved-2BC9> +2BCA..2BD1 ; Pattern_Syntax # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN +2BD2..2BFF ; Pattern_Syntax # Cn [46] <reserved-2BD2>..<reserved-2BFF> 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 @@ -1342,7 +1466,11 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 2E2F ; Pattern_Syntax # Lm VERTICAL TILDE 2E30..2E39 ; Pattern_Syntax # Po [10] RING POINT..TOP HALF SECTION SIGN 2E3A..2E3B ; Pattern_Syntax # Pd [2] TWO-EM DASH..THREE-EM DASH -2E3C..2E7F ; Pattern_Syntax # Cn [68] <reserved-2E3C>..<reserved-2E7F> +2E3C..2E3F ; Pattern_Syntax # Po [4] STENOGRAPHIC FULL STOP..CAPITULUM +2E40 ; Pattern_Syntax # Pd DOUBLE HYPHEN +2E41 ; Pattern_Syntax # Po REVERSED COMMA +2E42 ; Pattern_Syntax # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43..2E7F ; Pattern_Syntax # Cn [61] <reserved-2E43>..<reserved-2E7F> 3001..3003 ; Pattern_Syntax # Po [3] IDEOGRAPHIC COMMA..DITTO MARK 3008 ; Pattern_Syntax # Ps LEFT ANGLE BRACKET 3009 ; Pattern_Syntax # Pe RIGHT ANGLE BRACKET @@ -1368,8 +1496,8 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 301E..301F ; Pattern_Syntax # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK 3020 ; Pattern_Syntax # So POSTAL MARK FACE 3030 ; Pattern_Syntax # Pd WAVY DASH -FD3E ; Pattern_Syntax # Ps ORNATE LEFT PARENTHESIS -FD3F ; Pattern_Syntax # Pe ORNATE RIGHT PARENTHESIS +FD3E ; Pattern_Syntax # Pe ORNATE LEFT PARENTHESIS +FD3F ; Pattern_Syntax # Ps ORNATE RIGHT PARENTHESIS FE45..FE46 ; Pattern_Syntax # Po [2] SESAME DOT..WHITE SESAME DOT # Total code points: 2760 diff --git a/jdk/test/java/lang/Character/PropertyValueAliases.txt b/jdk/test/java/lang/Character/PropertyValueAliases.txt index d9048fb32f7..bf1e2eb83c4 100644 --- a/jdk/test/java/lang/Character/PropertyValueAliases.txt +++ b/jdk/test/java/lang/Character/PropertyValueAliases.txt @@ -1,8 +1,8 @@ -# PropertyValueAliases-6.2.0.txt -# Date: 2012-08-14, 16:05:11 GMT [MD] +# PropertyValueAliases-7.0.0.txt +# Date: 2014-05-14, 23:55:16 GMT [MD] # # Unicode Character Database -# Copyright (c) 1991-2012 Unicode, Inc. +# Copyright (c) 1991-2014 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # For documentation, see http://www.unicode.org/reports/tr44/ # @@ -32,13 +32,14 @@ # # Loose matching should be applied to all property names and property values, with # the exception of String Property values. With loose matching of property names and -# values, the case distinctions, whitespace, and '_' are ignored. For Numeric Property -# values, numeric equivalencies are applied: thus "01.00" is equivalent to "1". +# values, the case distinctions, whitespace, hyphens, and '_' are ignored. +# For Numeric Property values, numeric equivalence is applied: thus "01.00" +# is equivalent to "1". # # NOTE: Property value names are NOT unique across properties. For example: # # AL means Arabic Letter for the Bidi_Class property, and -# AL means Above_Left for the Combining_Class property, and +# AL means Above_Left for the Canonical_Combining_Class property, and # AL means Alphabetic for the Line_Break property. # # In addition, some property names may be the same as some property value names. @@ -74,6 +75,8 @@ age; 5.2 ; V5_2 age; 6.0 ; V6_0 age; 6.1 ; V6_1 age; 6.2 ; V6_2 +age; 6.3 ; V6_3 +age; 7.0 ; V7_0 age; NA ; Unassigned # Alphabetic (Alpha) @@ -91,14 +94,18 @@ bc ; CS ; Common_Separator bc ; EN ; European_Number bc ; ES ; European_Separator bc ; ET ; European_Terminator +bc ; FSI ; First_Strong_Isolate bc ; L ; Left_To_Right bc ; LRE ; Left_To_Right_Embedding +bc ; LRI ; Left_To_Right_Isolate bc ; LRO ; Left_To_Right_Override bc ; NSM ; Nonspacing_Mark bc ; ON ; Other_Neutral bc ; PDF ; Pop_Directional_Format +bc ; PDI ; Pop_Directional_Isolate bc ; R ; Right_To_Left bc ; RLE ; Right_To_Left_Embedding +bc ; RLI ; Right_To_Left_Isolate bc ; RLO ; Right_To_Left_Override bc ; S ; Segment_Separator bc ; WS ; White_Space @@ -117,6 +124,17 @@ Bidi_M; Y ; Yes ; T # @missing: 0000..10FFFF; Bidi_Mirroring_Glyph; <none> +# Bidi_Paired_Bracket (bpb) + +# @missing: 0000..10FFFF; Bidi_Paired_Bracket; <none> + +# Bidi_Paired_Bracket_Type (bpt) + +bpt; c ; Close +bpt; n ; None +bpt; o ; Open +# @missing: 0000..10FFFF; Bidi_Paired_Bracket_Type; n + # Block (blk) blk; Aegean_Numbers ; Aegean_Numbers @@ -138,6 +156,7 @@ blk; Avestan ; Avestan blk; Balinese ; Balinese blk; Bamum ; Bamum blk; Bamum_Sup ; Bamum_Supplement +blk; Bassa_Vah ; Bassa_Vah blk; Batak ; Batak blk; Bengali ; Bengali blk; Block_Elements ; Block_Elements @@ -150,6 +169,7 @@ blk; Buginese ; Buginese blk; Buhid ; Buhid blk; Byzantine_Music ; Byzantine_Musical_Symbols blk; Carian ; Carian +blk; Caucasian_Albanian ; Caucasian_Albanian blk; Chakma ; Chakma blk; Cham ; Cham blk; Cherokee ; Cherokee @@ -168,6 +188,7 @@ blk; CJK_Symbols ; CJK_Symbols_And_Punctuation blk; Compat_Jamo ; Hangul_Compatibility_Jamo blk; Control_Pictures ; Control_Pictures blk; Coptic ; Coptic +blk; Coptic_Epact_Numbers ; Coptic_Epact_Numbers blk; Counting_Rod ; Counting_Rod_Numerals blk; Cuneiform ; Cuneiform blk; Cuneiform_Numbers ; Cuneiform_Numbers_And_Punctuation @@ -181,11 +202,14 @@ blk; Deseret ; Deseret blk; Devanagari ; Devanagari blk; Devanagari_Ext ; Devanagari_Extended blk; Diacriticals ; Combining_Diacritical_Marks +blk; Diacriticals_Ext ; Combining_Diacritical_Marks_Extended blk; Diacriticals_For_Symbols ; Combining_Diacritical_Marks_For_Symbols; Combining_Marks_For_Symbols blk; Diacriticals_Sup ; Combining_Diacritical_Marks_Supplement blk; Dingbats ; Dingbats blk; Domino ; Domino_Tiles +blk; Duployan ; Duployan blk; Egyptian_Hieroglyphs ; Egyptian_Hieroglyphs +blk; Elbasan ; Elbasan blk; Emoticons ; Emoticons blk; Enclosed_Alphanum ; Enclosed_Alphanumerics blk; Enclosed_Alphanum_Sup ; Enclosed_Alphanumeric_Supplement @@ -196,10 +220,12 @@ blk; Ethiopic_Ext ; Ethiopic_Extended blk; Ethiopic_Ext_A ; Ethiopic_Extended_A blk; Ethiopic_Sup ; Ethiopic_Supplement blk; Geometric_Shapes ; Geometric_Shapes +blk; Geometric_Shapes_Ext ; Geometric_Shapes_Extended blk; Georgian ; Georgian blk; Georgian_Sup ; Georgian_Supplement blk; Glagolitic ; Glagolitic blk; Gothic ; Gothic +blk; Grantha ; Grantha blk; Greek ; Greek_And_Coptic blk; Greek_Ext ; Greek_Extended blk; Gujarati ; Gujarati @@ -233,6 +259,8 @@ blk; Kayah_Li ; Kayah_Li blk; Kharoshthi ; Kharoshthi blk; Khmer ; Khmer blk; Khmer_Symbols ; Khmer_Symbols +blk; Khojki ; Khojki +blk; Khudawadi ; Khudawadi blk; Lao ; Lao blk; Latin_1_Sup ; Latin_1_Supplement ; Latin_1 blk; Latin_Ext_A ; Latin_Extended_A @@ -240,22 +268,27 @@ blk; Latin_Ext_Additional ; Latin_Extended_Additional blk; Latin_Ext_B ; Latin_Extended_B blk; Latin_Ext_C ; Latin_Extended_C blk; Latin_Ext_D ; Latin_Extended_D +blk; Latin_Ext_E ; Latin_Extended_E blk; Lepcha ; Lepcha blk; Letterlike_Symbols ; Letterlike_Symbols blk; Limbu ; Limbu +blk; Linear_A ; Linear_A blk; Linear_B_Ideograms ; Linear_B_Ideograms blk; Linear_B_Syllabary ; Linear_B_Syllabary blk; Lisu ; Lisu blk; Low_Surrogates ; Low_Surrogates blk; Lycian ; Lycian blk; Lydian ; Lydian +blk; Mahajani ; Mahajani blk; Mahjong ; Mahjong_Tiles blk; Malayalam ; Malayalam blk; Mandaic ; Mandaic +blk; Manichaean ; Manichaean blk; Math_Alphanum ; Mathematical_Alphanumeric_Symbols blk; Math_Operators ; Mathematical_Operators blk; Meetei_Mayek ; Meetei_Mayek blk; Meetei_Mayek_Ext ; Meetei_Mayek_Extensions +blk; Mende_Kikakui ; Mende_Kikakui blk; Meroitic_Cursive ; Meroitic_Cursive blk; Meroitic_Hieroglyphs ; Meroitic_Hieroglyphs blk; Miao ; Miao @@ -265,12 +298,16 @@ blk; Misc_Math_Symbols_B ; Miscellaneous_Mathematical_Symbols_B blk; Misc_Pictographs ; Miscellaneous_Symbols_And_Pictographs blk; Misc_Symbols ; Miscellaneous_Symbols blk; Misc_Technical ; Miscellaneous_Technical +blk; Modi ; Modi blk; Modifier_Letters ; Spacing_Modifier_Letters blk; Modifier_Tone_Letters ; Modifier_Tone_Letters blk; Mongolian ; Mongolian +blk; Mro ; Mro blk; Music ; Musical_Symbols blk; Myanmar ; Myanmar blk; Myanmar_Ext_A ; Myanmar_Extended_A +blk; Myanmar_Ext_B ; Myanmar_Extended_B +blk; Nabataean ; Nabataean blk; NB ; No_Block blk; New_Tai_Lue ; New_Tai_Lue blk; NKo ; NKo @@ -279,17 +316,24 @@ blk; OCR ; Optical_Character_Recognition blk; Ogham ; Ogham blk; Ol_Chiki ; Ol_Chiki blk; Old_Italic ; Old_Italic +blk; Old_North_Arabian ; Old_North_Arabian +blk; Old_Permic ; Old_Permic blk; Old_Persian ; Old_Persian blk; Old_South_Arabian ; Old_South_Arabian blk; Old_Turkic ; Old_Turkic blk; Oriya ; Oriya +blk; Ornamental_Dingbats ; Ornamental_Dingbats blk; Osmanya ; Osmanya +blk; Pahawh_Hmong ; Pahawh_Hmong +blk; Palmyrene ; Palmyrene +blk; Pau_Cin_Hau ; Pau_Cin_Hau blk; Phags_Pa ; Phags_Pa blk; Phaistos ; Phaistos_Disc blk; Phoenician ; Phoenician blk; Phonetic_Ext ; Phonetic_Extensions blk; Phonetic_Ext_Sup ; Phonetic_Extensions_Supplement blk; Playing_Cards ; Playing_Cards +blk; Psalter_Pahlavi ; Psalter_Pahlavi blk; PUA ; Private_Use_Area ; Private_Use blk; Punctuation ; General_Punctuation blk; Rejang ; Rejang @@ -299,7 +343,10 @@ blk; Samaritan ; Samaritan blk; Saurashtra ; Saurashtra blk; Sharada ; Sharada blk; Shavian ; Shavian +blk; Shorthand_Format_Controls ; Shorthand_Format_Controls +blk; Siddham ; Siddham blk; Sinhala ; Sinhala +blk; Sinhala_Archaic_Numbers ; Sinhala_Archaic_Numbers blk; Small_Forms ; Small_Form_Variants blk; Sora_Sompeng ; Sora_Sompeng blk; Specials ; Specials @@ -307,6 +354,7 @@ blk; Sundanese ; Sundanese blk; Sundanese_Sup ; Sundanese_Supplement blk; Sup_Arrows_A ; Supplemental_Arrows_A blk; Sup_Arrows_B ; Supplemental_Arrows_B +blk; Sup_Arrows_C ; Supplemental_Arrows_C blk; Sup_Math_Operators ; Supplemental_Mathematical_Operators blk; Sup_PUA_A ; Supplementary_Private_Use_Area_A blk; Sup_PUA_B ; Supplementary_Private_Use_Area_B @@ -328,6 +376,7 @@ blk; Thaana ; Thaana blk; Thai ; Thai blk; Tibetan ; Tibetan blk; Tifinagh ; Tifinagh +blk; Tirhuta ; Tirhuta blk; Transport_And_Map ; Transport_And_Map_Symbols blk; UCAS ; Unified_Canadian_Aboriginal_Syllabics; Canadian_Syllabics blk; UCAS_Ext ; Unified_Canadian_Aboriginal_Syllabics_Extended @@ -337,6 +386,7 @@ blk; Vedic_Ext ; Vedic_Extensions blk; Vertical_Forms ; Vertical_Forms blk; VS ; Variation_Selectors blk; VS_Sup ; Variation_Selectors_Supplement +blk; Warang_Citi ; Warang_Citi blk; Yi_Radicals ; Yi_Radicals blk; Yi_Syllables ; Yi_Syllables blk; Yijing ; Yijing_Hexagram_Symbols @@ -578,6 +628,7 @@ gc ; Z ; Separator # Zl | gc ; Zl ; Line_Separator gc ; Zp ; Paragraph_Separator gc ; Zs ; Space_Separator +# @missing: 0000..10FFFF; General_Category; Unassigned # Grapheme_Base (Gr_Base) @@ -662,7 +713,6 @@ Ideo; Y ; Yes ; T InMC; Bottom ; Bottom InMC; Bottom_And_Right ; Bottom_And_Right -InMC; Invisible ; Invisible InMC; Left ; Left InMC; Left_And_Right ; Left_And_Right InMC; NA ; NA @@ -680,17 +730,27 @@ InMC; Visual_Order_Left ; Visual_Order_Left InSC; Avagraha ; Avagraha InSC; Bindu ; Bindu +InSC; Brahmi_Joining_Number ; Brahmi_Joining_Number +InSC; Cantillation_Mark ; Cantillation_Mark InSC; Consonant ; Consonant InSC; Consonant_Dead ; Consonant_Dead InSC; Consonant_Final ; Consonant_Final InSC; Consonant_Head_Letter ; Consonant_Head_Letter InSC; Consonant_Medial ; Consonant_Medial InSC; Consonant_Placeholder ; Consonant_Placeholder -InSC; Consonant_Repha ; Consonant_Repha +InSC; Consonant_Preceding_Repha ; Consonant_Preceding_Repha InSC; Consonant_Subjoined ; Consonant_Subjoined +InSC; Consonant_Succeeding_Repha ; Consonant_Succeeding_Repha +InSC; Gemination_Mark ; Gemination_Mark +InSC; Invisible_Stacker ; Invisible_Stacker +InSC; Joiner ; Joiner InSC; Modifying_Letter ; Modifying_Letter +InSC; Non_Joiner ; Non_Joiner InSC; Nukta ; Nukta +InSC; Number ; Number +InSC; Number_Joiner ; Number_Joiner InSC; Other ; Other +InSC; Pure_Killer ; Pure_Killer InSC; Register_Shifter ; Register_Shifter InSC; Tone_Letter ; Tone_Letter InSC; Tone_Mark ; Tone_Mark @@ -702,7 +762,6 @@ InSC; Vowel_Independent ; Vowel_Independent # Jamo_Short_Name (JSN) -# @missing: 0000..10FFFF; Jamo_Short_Name; <none> JSN; A ; A JSN; AE ; AE JSN; B ; B @@ -755,6 +814,7 @@ JSN; YEO ; YEO JSN; YI ; YI JSN; YO ; YO JSN; YU ; YU +# @missing: 0000..10FFFF; Jamo_Short_Name; <none> # Join_Control (Join_C) @@ -789,6 +849,33 @@ jg ; Khaph ; Khaph jg ; Knotted_Heh ; Knotted_Heh jg ; Lam ; Lam jg ; Lamadh ; Lamadh +jg ; Manichaean_Aleph ; Manichaean_Aleph +jg ; Manichaean_Ayin ; Manichaean_Ayin +jg ; Manichaean_Beth ; Manichaean_Beth +jg ; Manichaean_Daleth ; Manichaean_Daleth +jg ; Manichaean_Dhamedh ; Manichaean_Dhamedh +jg ; Manichaean_Five ; Manichaean_Five +jg ; Manichaean_Gimel ; Manichaean_Gimel +jg ; Manichaean_Heth ; Manichaean_Heth +jg ; Manichaean_Hundred ; Manichaean_Hundred +jg ; Manichaean_Kaph ; Manichaean_Kaph +jg ; Manichaean_Lamedh ; Manichaean_Lamedh +jg ; Manichaean_Mem ; Manichaean_Mem +jg ; Manichaean_Nun ; Manichaean_Nun +jg ; Manichaean_One ; Manichaean_One +jg ; Manichaean_Pe ; Manichaean_Pe +jg ; Manichaean_Qoph ; Manichaean_Qoph +jg ; Manichaean_Resh ; Manichaean_Resh +jg ; Manichaean_Sadhe ; Manichaean_Sadhe +jg ; Manichaean_Samekh ; Manichaean_Samekh +jg ; Manichaean_Taw ; Manichaean_Taw +jg ; Manichaean_Ten ; Manichaean_Ten +jg ; Manichaean_Teth ; Manichaean_Teth +jg ; Manichaean_Thamedh ; Manichaean_Thamedh +jg ; Manichaean_Twenty ; Manichaean_Twenty +jg ; Manichaean_Waw ; Manichaean_Waw +jg ; Manichaean_Yodh ; Manichaean_Yodh +jg ; Manichaean_Zayin ; Manichaean_Zayin jg ; Meem ; Meem jg ; Mim ; Mim jg ; No_Joining_Group ; No_Joining_Group @@ -806,6 +893,7 @@ jg ; Sadhe ; Sadhe jg ; Seen ; Seen jg ; Semkath ; Semkath jg ; Shin ; Shin +jg ; Straight_Waw ; Straight_Waw jg ; Swash_Kaf ; Swash_Kaf jg ; Syriac_Waw ; Syriac_Waw jg ; Tah ; Tah @@ -884,6 +972,10 @@ LOE; Y ; Yes ; T Lower; N ; No ; F ; False Lower; Y ; Yes ; T ; True +# Lowercase_Mapping (lc) + +# @missing: 0000..10FFFF; Lowercase_Mapping; <code point> + # Math (Math) Math; N ; No ; F ; False @@ -1006,12 +1098,14 @@ STerm; Y ; Yes ; T # Script (sc) +sc ; Aghb ; Caucasian_Albanian sc ; Arab ; Arabic sc ; Armi ; Imperial_Aramaic sc ; Armn ; Armenian sc ; Avst ; Avestan sc ; Bali ; Balinese sc ; Bamu ; Bamum +sc ; Bass ; Bassa_Vah sc ; Batk ; Batak sc ; Beng ; Bengali sc ; Bopo ; Bopomofo @@ -1029,11 +1123,14 @@ sc ; Cprt ; Cypriot sc ; Cyrl ; Cyrillic sc ; Deva ; Devanagari sc ; Dsrt ; Deseret +sc ; Dupl ; Duployan sc ; Egyp ; Egyptian_Hieroglyphs +sc ; Elba ; Elbasan sc ; Ethi ; Ethiopic sc ; Geor ; Georgian sc ; Glag ; Glagolitic sc ; Goth ; Gothic +sc ; Gran ; Grantha sc ; Grek ; Greek sc ; Gujr ; Gujarati sc ; Guru ; Gurmukhi @@ -1042,6 +1139,7 @@ sc ; Hani ; Han sc ; Hano ; Hanunoo sc ; Hebr ; Hebrew sc ; Hira ; Hiragana +sc ; Hmng ; Pahawh_Hmong sc ; Hrkt ; Katakana_Or_Hiragana sc ; Ital ; Old_Italic sc ; Java ; Javanese @@ -1049,6 +1147,7 @@ sc ; Kali ; Kayah_Li sc ; Kana ; Katakana sc ; Khar ; Kharoshthi sc ; Khmr ; Khmer +sc ; Khoj ; Khojki sc ; Knda ; Kannada sc ; Kthi ; Kaithi sc ; Lana ; Tai_Tham @@ -1056,25 +1155,37 @@ sc ; Laoo ; Lao sc ; Latn ; Latin sc ; Lepc ; Lepcha sc ; Limb ; Limbu +sc ; Lina ; Linear_A sc ; Linb ; Linear_B sc ; Lisu ; Lisu sc ; Lyci ; Lycian sc ; Lydi ; Lydian +sc ; Mahj ; Mahajani sc ; Mand ; Mandaic +sc ; Mani ; Manichaean +sc ; Mend ; Mende_Kikakui sc ; Merc ; Meroitic_Cursive sc ; Mero ; Meroitic_Hieroglyphs sc ; Mlym ; Malayalam +sc ; Modi ; Modi sc ; Mong ; Mongolian +sc ; Mroo ; Mro sc ; Mtei ; Meetei_Mayek sc ; Mymr ; Myanmar +sc ; Narb ; Old_North_Arabian +sc ; Nbat ; Nabataean sc ; Nkoo ; Nko sc ; Ogam ; Ogham sc ; Olck ; Ol_Chiki sc ; Orkh ; Old_Turkic sc ; Orya ; Oriya sc ; Osma ; Osmanya +sc ; Palm ; Palmyrene +sc ; Pauc ; Pau_Cin_Hau +sc ; Perm ; Old_Permic sc ; Phag ; Phags_Pa sc ; Phli ; Inscriptional_Pahlavi +sc ; Phlp ; Psalter_Pahlavi sc ; Phnx ; Phoenician sc ; Plrd ; Miao sc ; Prti ; Inscriptional_Parthian @@ -1085,6 +1196,8 @@ sc ; Sarb ; Old_South_Arabian sc ; Saur ; Saurashtra sc ; Shaw ; Shavian sc ; Shrd ; Sharada +sc ; Sidd ; Siddham +sc ; Sind ; Khudawadi sc ; Sinh ; Sinhala sc ; Sora ; Sora_Sompeng sc ; Sund ; Sundanese @@ -1102,8 +1215,10 @@ sc ; Tglg ; Tagalog sc ; Thaa ; Thaana sc ; Thai ; Thai sc ; Tibt ; Tibetan +sc ; Tirh ; Tirhuta sc ; Ugar ; Ugaritic sc ; Vaii ; Vai +sc ; Wara ; Warang_Citi sc ; Xpeo ; Old_Persian sc ; Xsux ; Cuneiform sc ; Yiii ; Yi @@ -1159,6 +1274,10 @@ SD ; Y ; Yes ; T Term; N ; No ; F ; False Term; Y ; Yes ; T ; True +# Titlecase_Mapping (tc) + +# @missing: 0000..10FFFF; Titlecase_Mapping; <code point> + # Unicode_1_Name (na1) # @missing: 0000..10FFFF; Unicode_1_Name; <none> @@ -1173,6 +1292,10 @@ UIdeo; Y ; Yes ; T Upper; N ; No ; F ; False Upper; Y ; Yes ; T ; True +# Uppercase_Mapping (uc) + +# @missing: 0000..10FFFF; Uppercase_Mapping; <code point> + # Variation_Selector (VS) VS ; N ; No ; F ; False @@ -1186,9 +1309,11 @@ WSpace; Y ; Yes ; T # Word_Break (WB) WB ; CR ; CR +WB ; DQ ; Double_Quote WB ; EX ; ExtendNumLet WB ; Extend ; Extend WB ; FO ; Format +WB ; HL ; Hebrew_Letter WB ; KA ; Katakana WB ; LE ; ALetter WB ; LF ; LF @@ -1198,6 +1323,7 @@ WB ; MN ; MidNum WB ; NL ; Newline WB ; NU ; Numeric WB ; RI ; Regional_Indicator +WB ; SQ ; Single_Quote WB ; XX ; Other # XID_Continue (XIDC) diff --git a/jdk/test/java/lang/Character/Scripts.txt b/jdk/test/java/lang/Character/Scripts.txt index 1a8e7229cc6..0b69438a571 100644 --- a/jdk/test/java/lang/Character/Scripts.txt +++ b/jdk/test/java/lang/Character/Scripts.txt @@ -1,8 +1,8 @@ -# Scripts-6.2.0.txt -# Date: 2012-06-04, 17:21:29 GMT [MD] +# Scripts-7.0.0.txt +# Date: 2014-05-15, 00:11:35 GMT [MD] # # Unicode Character Database -# Copyright (c) 1991-2012 Unicode, Inc. +# Copyright (c) 1991-2014 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # For documentation, see http://www.unicode.org/reports/tr44/ @@ -83,8 +83,10 @@ 0385 ; Common # Sk GREEK DIALYTIKA TONOS 0387 ; Common # Po GREEK ANO TELEIA 0589 ; Common # Po ARMENIAN FULL STOP +0605 ; Common # Cf ARABIC NUMBER MARK ABOVE 060C ; Common # Po ARABIC COMMA 061B ; Common # Po ARABIC SEMICOLON +061C ; Common # Cf ARABIC LETTER MARK 061F ; Common # Po ARABIC QUESTION MARK 0640 ; Common # Lm ARABIC TATWEEL 0660..0669 ; Common # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE @@ -136,7 +138,7 @@ 2055..205E ; Common # Po [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS 205F ; Common # Zs MEDIUM MATHEMATICAL SPACE 2060..2064 ; Common # Cf [5] WORD JOINER..INVISIBLE PLUS -206A..206F ; Common # Cf [6] INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES +2066..206F ; Common # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES 2070 ; Common # No SUPERSCRIPT ZERO 2074..2079 ; Common # No [6] SUPERSCRIPT FOUR..SUPERSCRIPT NINE 207A..207C ; Common # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN @@ -146,7 +148,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..20BA ; Common # Sc [27] EURO-CURRENCY SIGN..TURKISH LIRA SIGN +20A0..20BD ; Common # Sc [30] EURO-CURRENCY SIGN..RUBLE 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 @@ -200,7 +202,10 @@ 21D5..21F3 ; Common # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW 21F4..22FF ; Common # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP 2300..2307 ; Common # So [8] DIAMETER SIGN..WAVY LINE -2308..230B ; Common # Sm [4] LEFT CEILING..RIGHT FLOOR +2308 ; Common # Ps LEFT CEILING +2309 ; Common # Pe RIGHT CEILING +230A ; Common # Ps LEFT FLOOR +230B ; Common # Pe RIGHT FLOOR 230C..231F ; Common # So [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER 2320..2321 ; Common # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL 2322..2328 ; Common # So [7] FROWN..KEYBOARD @@ -212,7 +217,7 @@ 239B..23B3 ; Common # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM 23B4..23DB ; Common # So [40] TOP SQUARE BRACKET..FUSE 23DC..23E1 ; Common # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET -23E2..23F3 ; Common # So [18] WHITE TRAPEZIUM..HOURGLASS WITH FLOWING SAND +23E2..23FA ; Common # So [25] WHITE TRAPEZIUM..BLACK CIRCLE FOR RECORD 2400..2426 ; Common # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO 2440..244A ; Common # So [11] OCR HOOK..OCR DOUBLE BACKSLASH 2460..249B ; Common # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP @@ -226,8 +231,7 @@ 25F8..25FF ; Common # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE 2600..266E ; Common # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN 266F ; Common # Sm MUSIC SHARP SIGN -2670..26FF ; Common # So [144] WEST SYRIAC CROSS..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE -2701..2767 ; Common # So [103] UPPER BLADE SCISSORS..ROTATED FLORAL HEART BULLET +2670..2767 ; Common # So [248] WEST SYRIAC CROSS..ROTATED FLORAL HEART BULLET 2768 ; Common # Ps MEDIUM LEFT PARENTHESIS ORNAMENT 2769 ; Common # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT 276A ; Common # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT @@ -295,7 +299,11 @@ 2B30..2B44 ; Common # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET 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 -2B50..2B59 ; Common # So [10] WHITE MEDIUM STAR..HEAVY CIRCLED SALTIRE +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 +2B98..2BB9 ; Common # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX +2BBD..2BC8 ; Common # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED +2BCA..2BD1 ; Common # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN 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 @@ -329,6 +337,10 @@ 2E2F ; Common # Lm VERTICAL TILDE 2E30..2E39 ; Common # Po [10] RING POINT..TOP HALF SECTION SIGN 2E3A..2E3B ; Common # Pd [2] TWO-EM DASH..THREE-EM DASH +2E3C..2E3F ; Common # Po [4] STENOGRAPHIC FULL STOP..CAPITULUM +2E40 ; Common # Pd DOUBLE HYPHEN +2E41 ; Common # Po REVERSED COMMA +2E42 ; Common # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK 2FF0..2FFB ; Common # So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID 3000 ; Common # Zs IDEOGRAPHIC SPACE 3001..3003 ; Common # Po [3] IDEOGRAPHIC COMMA..DITTO MARK @@ -392,9 +404,11 @@ A830..A835 ; Common # No [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC A836..A837 ; Common # So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK A838 ; Common # Sc NORTH INDIC RUPEE MARK A839 ; Common # So NORTH INDIC QUANTITY MARK -FD3E ; Common # Ps ORNATE LEFT PARENTHESIS -FD3F ; Common # Pe ORNATE RIGHT PARENTHESIS -FDFD ; Common # So ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM +A92E ; Common # Po KAYAH LI SIGN CWI +A9CF ; Common # Lm JAVANESE PANGRANGKEP +AB5B ; Common # Sk MODIFIER BREVE WITH INVERTED BREVE +FD3E ; Common # Pe ORNATE LEFT PARENTHESIS +FD3F ; Common # Ps ORNATE RIGHT PARENTHESIS FE10..FE16 ; Common # Po [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK FE17 ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET FE18 ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET @@ -487,6 +501,8 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 10137..1013F ; Common # So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT 10190..1019B ; Common # So [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN 101D0..101FC ; Common # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND +102E1..102FB ; Common # No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED +1BCA0..1BCA3 ; Common # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP 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 1D129..1D164 ; Common # So [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE @@ -543,10 +559,10 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1F000..1F02B ; Common # So [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK 1F030..1F093 ; Common # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06 1F0A0..1F0AE ; Common # So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES -1F0B1..1F0BE ; Common # So [14] PLAYING CARD ACE OF HEARTS..PLAYING CARD KING OF HEARTS +1F0B1..1F0BF ; Common # So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER 1F0C1..1F0CF ; Common # So [15] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER -1F0D1..1F0DF ; Common # So [15] PLAYING CARD ACE OF CLUBS..PLAYING CARD WHITE JOKER -1F100..1F10A ; Common # No [11] DIGIT ZERO FULL STOP..DIGIT NINE COMMA +1F0D1..1F0F5 ; Common # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21 +1F100..1F10C ; Common # No [13] DIGIT ZERO FULL STOP..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO 1F110..1F12E ; Common # So [31] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED WZ 1F130..1F16B ; Common # So [60] SQUARED LATIN CAPITAL LETTER A..RAISED MD SIGN 1F170..1F19A ; Common # So [43] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VS @@ -555,28 +571,29 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1F210..1F23A ; Common # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6 1F240..1F248 ; Common # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 1F250..1F251 ; Common # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT -1F300..1F320 ; Common # So [33] CYCLONE..SHOOTING STAR -1F330..1F335 ; Common # So [6] CHESTNUT..CACTUS -1F337..1F37C ; Common # So [70] TULIP..BABY BOTTLE -1F380..1F393 ; Common # So [20] RIBBON..GRADUATION CAP -1F3A0..1F3C4 ; Common # So [37] CAROUSEL HORSE..SURFER -1F3C6..1F3CA ; Common # So [5] TROPHY..SWIMMER -1F3E0..1F3F0 ; Common # So [17] HOUSE BUILDING..EUROPEAN CASTLE -1F400..1F43E ; Common # So [63] RAT..PAW PRINTS -1F440 ; Common # So EYES -1F442..1F4F7 ; Common # So [182] EAR..CAMERA -1F4F9..1F4FC ; Common # So [4] VIDEO CAMERA..VIDEOCASSETTE -1F500..1F53D ; Common # So [62] TWISTED RIGHTWARDS ARROWS..DOWN-POINTING SMALL RED TRIANGLE -1F540..1F543 ; Common # So [4] CIRCLED CROSS POMMEE..NOTCHED LEFT SEMICIRCLE WITH THREE DOTS -1F550..1F567 ; Common # So [24] CLOCK FACE ONE OCLOCK..CLOCK FACE TWELVE-THIRTY -1F5FB..1F640 ; Common # So [70] MOUNT FUJI..WEARY CAT FACE -1F645..1F64F ; Common # So [11] FACE WITH NO GOOD GESTURE..PERSON WITH FOLDED HANDS -1F680..1F6C5 ; Common # So [70] ROCKET..LEFT LUGGAGE +1F300..1F32C ; Common # So [45] CYCLONE..WIND BLOWING FACE +1F330..1F37D ; Common # So [78] CHESTNUT..FORK AND KNIFE WITH PLATE +1F380..1F3CE ; Common # So [79] RIBBON..RACING CAR +1F3D4..1F3F7 ; Common # So [36] SNOW CAPPED MOUNTAIN..LABEL +1F400..1F4FE ; Common # So [255] RAT..PORTABLE STEREO +1F500..1F54A ; Common # So [75] TWISTED RIGHTWARDS ARROWS..DOVE OF PEACE +1F550..1F579 ; Common # So [42] CLOCK FACE ONE OCLOCK..JOYSTICK +1F57B..1F5A3 ; Common # So [41] LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX +1F5A5..1F642 ; Common # So [158] DESKTOP COMPUTER..SLIGHTLY SMILING FACE +1F645..1F6CF ; Common # So [139] FACE WITH NO GOOD GESTURE..BED +1F6E0..1F6EC ; Common # So [13] HAMMER AND WRENCH..AIRPLANE ARRIVING +1F6F0..1F6F3 ; Common # So [4] SATELLITE..PASSENGER SHIP 1F700..1F773 ; Common # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE +1F780..1F7D4 ; Common # So [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR +1F800..1F80B ; Common # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD +1F810..1F847 ; Common # So [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW +1F850..1F859 ; Common # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW +1F860..1F887 ; Common # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW +1F890..1F8AD ; Common # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS E0001 ; Common # Cf LANGUAGE TAG E0020..E007F ; Common # Cf [96] TAG SPACE..CANCEL TAG -# Total code points: 6413 +# Total code points: 7129 # ================================================ @@ -618,16 +635,20 @@ A722..A76F ; Latin # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN 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 -A790..A793 ; Latin # L& [4] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER C WITH BAR -A7A0..A7AA ; Latin # L& [11] LATIN CAPITAL LETTER G WITH OBLIQUE STROKE..LATIN CAPITAL LETTER H WITH HOOK +A790..A7AD ; Latin # L& [30] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER L WITH BELT +A7B0..A7B1 ; Latin # L& [2] LATIN CAPITAL LETTER TURNED K..LATIN CAPITAL LETTER TURNED T +A7F7 ; Latin # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; Latin # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE A7FA ; Latin # L& LATIN LETTER SMALL CAPITAL TURNED M A7FB..A7FF ; Latin # Lo [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M +AB30..AB5A ; Latin # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG +AB5C..AB5F ; Latin # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK +AB64 ; Latin # L& LATIN SMALL LETTER INVERTED ALPHA FB00..FB06 ; Latin # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST FF21..FF3A ; Latin # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z -# Total code points: 1272 +# Total code points: 1338 # ================================================ @@ -636,6 +657,7 @@ FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 0376..0377 ; Greek # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA 037A ; Greek # Lm GREEK YPOGEGRAMMENI 037B..037D ; Greek # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL +037F ; Greek # L& GREEK CAPITAL LETTER YOT 0384 ; Greek # Sk GREEK TONOS 0386 ; Greek # L& GREEK CAPITAL LETTER ALPHA WITH TONOS 0388..038A ; Greek # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS @@ -675,15 +697,18 @@ FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 1FF6..1FFC ; Greek # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI 1FFD..1FFE ; Greek # Sk [2] GREEK OXIA..GREEK DASIA 2126 ; Greek # L& OHM SIGN +AB65 ; Greek # L& GREEK LETTER SMALL CAPITAL OMEGA 10140..10174 ; Greek # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS 10175..10178 ; Greek # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN 10179..10189 ; Greek # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN -1018A ; Greek # No GREEK ZERO SIGN +1018A..1018B ; Greek # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN +1018C ; Greek # So GREEK SINUSOID SIGN +101A0 ; Greek # So GREEK SYMBOL TAU RHO 1D200..1D241 ; Greek # So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54 1D242..1D244 ; Greek # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME 1D245 ; Greek # So GREEK MUSICAL LEIMMA -# Total code points: 511 +# Total code points: 516 # ================================================ @@ -692,7 +717,7 @@ FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 0483..0484 ; Cyrillic # Mn [2] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC PALATALIZATION 0487 ; Cyrillic # Mn COMBINING CYRILLIC POKRYTIE 0488..0489 ; Cyrillic # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN -048A..0527 ; Cyrillic # L& [158] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER SHHA WITH DESCENDER +048A..052F ; Cyrillic # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER 1D2B ; Cyrillic # L& CYRILLIC LETTER SMALL CAPITAL EL 1D78 ; Cyrillic # Lm MODIFIER LETTER CYRILLIC EN 2DE0..2DFF ; Cyrillic # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS @@ -704,10 +729,11 @@ A673 ; Cyrillic # Po SLAVONIC ASTERISK A674..A67D ; Cyrillic # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK A67E ; Cyrillic # Po CYRILLIC KAVYKA A67F ; Cyrillic # Lm CYRILLIC PAYEROK -A680..A697 ; Cyrillic # L& [24] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER SHWE +A680..A69B ; Cyrillic # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O +A69C..A69D ; Cyrillic # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN A69F ; Cyrillic # Mn COMBINING CYRILLIC LETTER IOTIFIED E -# Total code points: 417 +# Total code points: 431 # ================================================ @@ -716,10 +742,11 @@ A69F ; Cyrillic # Mn COMBINING CYRILLIC LETTER IOTIFIED E 055A..055F ; Armenian # Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK 0561..0587 ; Armenian # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN 058A ; Armenian # Pd ARMENIAN HYPHEN +058D..058E ; Armenian # So [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN 058F ; Armenian # Sc ARMENIAN DRAM SIGN FB13..FB17 ; Armenian # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH -# Total code points: 91 +# Total code points: 93 # ================================================ @@ -779,9 +806,8 @@ FB46..FB4F ; Hebrew # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATU 06FD..06FE ; Arabic # So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN 06FF ; Arabic # Lo ARABIC LETTER HEH WITH INVERTED V 0750..077F ; Arabic # Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE -08A0 ; Arabic # Lo ARABIC LETTER BEH WITH SMALL V BELOW -08A2..08AC ; Arabic # Lo [11] ARABIC LETTER JEEM WITH TWO DOTS ABOVE..ARABIC LETTER ROHINGYA YEH -08E4..08FE ; Arabic # Mn [27] ARABIC CURLY FATHA..ARABIC DAMMA WITH DOT +08A0..08B2 ; Arabic # Lo [19] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER ZAIN WITH INVERTED V ABOVE +08E4..08FF ; Arabic # Mn [28] ARABIC CURLY FATHA..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..FBC1 ; Arabic # Sk [16] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL SMALL TAH BELOW FBD3..FD3D ; Arabic # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM @@ -789,6 +815,7 @@ FD50..FD8F ; Arabic # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIA FD92..FDC7 ; Arabic # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM FDF0..FDFB ; Arabic # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU FDFC ; Arabic # Sc RIAL SIGN +FDFD ; Arabic # So ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM FE70..FE74 ; Arabic # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM 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 @@ -827,7 +854,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: 1235 +# Total code points: 1244 # ================================================ @@ -870,17 +897,17 @@ FE76..FEFC ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LA 0966..096F ; Devanagari # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE 0970 ; Devanagari # Po DEVANAGARI ABBREVIATION SIGN 0971 ; Devanagari # Lm DEVANAGARI SIGN HIGH SPACING DOT -0972..0977 ; Devanagari # Lo [6] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER UUE -0979..097F ; Devanagari # Lo [7] DEVANAGARI LETTER ZHA..DEVANAGARI LETTER BBA +0972..097F ; Devanagari # Lo [14] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER BBA A8E0..A8F1 ; Devanagari # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA A8F2..A8F7 ; Devanagari # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA A8F8..A8FA ; Devanagari # Po [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE -# Total code points: 151 +# Total code points: 152 # ================================================ +0980 ; Bengali # Lo BENGALI ANJI 0981 ; Bengali # Mn BENGALI SIGN CANDRABINDU 0982..0983 ; Bengali # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA 0985..098C ; Bengali # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L @@ -908,7 +935,7 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 09FA ; Bengali # So BENGALI ISSHAR 09FB ; Bengali # Sc BENGALI GANDA MARK -# Total code points: 92 +# Total code points: 93 # ================================================ @@ -1025,12 +1052,12 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE # ================================================ +0C00 ; Telugu # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE 0C01..0C03 ; Telugu # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA 0C05..0C0C ; Telugu # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L 0C0E..0C10 ; Telugu # Lo [3] TELUGU LETTER E..TELUGU LETTER AI 0C12..0C28 ; Telugu # Lo [23] TELUGU LETTER O..TELUGU LETTER NA -0C2A..0C33 ; Telugu # Lo [10] TELUGU LETTER PA..TELUGU LETTER LLA -0C35..0C39 ; Telugu # Lo [5] TELUGU LETTER VA..TELUGU LETTER HA +0C2A..0C39 ; Telugu # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA 0C3D ; Telugu # Lo TELUGU SIGN AVAGRAHA 0C3E..0C40 ; Telugu # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II 0C41..0C44 ; Telugu # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR @@ -1044,10 +1071,11 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 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: 93 +# Total code points: 95 # ================================================ +0C81 ; Kannada # Mn KANNADA SIGN CANDRABINDU 0C82..0C83 ; Kannada # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 0C85..0C8C ; Kannada # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L 0C8E..0C90 ; Kannada # Lo [3] KANNADA LETTER E..KANNADA LETTER AI @@ -1070,10 +1098,11 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 0CE6..0CEF ; Kannada # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE 0CF1..0CF2 ; Kannada # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA -# Total code points: 86 +# Total code points: 87 # ================================================ +0D01 ; Malayalam # Mn MALAYALAM SIGN CANDRABINDU 0D02..0D03 ; Malayalam # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D05..0D0C ; Malayalam # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L 0D0E..0D10 ; Malayalam # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI @@ -1093,7 +1122,7 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 0D79 ; Malayalam # So MALAYALAM DATE MARK 0D7A..0D7F ; Malayalam # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K -# Total code points: 98 +# Total code points: 99 # ================================================ @@ -1108,10 +1137,12 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 0DD2..0DD4 ; Sinhala # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA 0DD6 ; Sinhala # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA 0DD8..0DDF ; Sinhala # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA +0DE6..0DEF ; Sinhala # Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE 0DF2..0DF3 ; Sinhala # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA 0DF4 ; Sinhala # Po SINHALA PUNCTUATION KUNDDALIYA +111E1..111F4 ; Sinhala # No [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND -# Total code points: 80 +# Total code points: 110 # ================================================ @@ -1234,14 +1265,23 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE 109A..109C ; Myanmar # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A 109D ; Myanmar # Mn MYANMAR VOWEL SIGN AITON AI 109E..109F ; Myanmar # So [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION +A9E0..A9E4 ; Myanmar # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA +A9E5 ; Myanmar # Mn MYANMAR SIGN SHAN SAW +A9E6 ; Myanmar # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION +A9E7..A9EF ; Myanmar # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA +A9F0..A9F9 ; Myanmar # Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE +A9FA..A9FE ; Myanmar # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA AA60..AA6F ; Myanmar # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA AA70 ; Myanmar # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION AA71..AA76 ; Myanmar # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM AA77..AA79 ; Myanmar # So [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO AA7A ; Myanmar # Lo MYANMAR LETTER AITON RA AA7B ; Myanmar # Mc MYANMAR SIGN PAO KAREN TONE +AA7C ; Myanmar # Mn MYANMAR SIGN TAI LAING TONE-2 +AA7D ; Myanmar # Mc MYANMAR SIGN TAI LAING TONE-5 +AA7E..AA7F ; Myanmar # Lo [2] MYANMAR LETTER SHWE PALAUNG CHA..MYANMAR LETTER SHWE PALAUNG SHA -# Total code points: 188 +# Total code points: 223 # ================================================ @@ -1345,8 +1385,9 @@ AB28..AB2E ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO 16A0..16EA ; Runic # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X 16EE..16F0 ; Runic # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL +16F1..16F8 ; Runic # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC -# Total code points: 78 +# Total code points: 86 # ================================================ @@ -1377,7 +1418,7 @@ AB28..AB2E ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO 1806 ; Mongolian # Pd MONGOLIAN TODO SOFT HYPHEN 1807..180A ; Mongolian # Po [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU 180B..180D ; Mongolian # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE -180E ; Mongolian # Zs MONGOLIAN VOWEL SEPARATOR +180E ; Mongolian # Cf MONGOLIAN VOWEL SEPARATOR 1810..1819 ; Mongolian # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE 1820..1842 ; Mongolian # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI 1843 ; Mongolian # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN @@ -1452,10 +1493,10 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE # ================================================ -10300..1031E ; Old_Italic # Lo [31] OLD ITALIC LETTER A..OLD ITALIC LETTER UU +10300..1031F ; Old_Italic # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS 10320..10323 ; Old_Italic # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY -# Total code points: 35 +# Total code points: 36 # ================================================ @@ -1479,12 +1520,15 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE 064B..0655 ; Inherited # Mn [11] ARABIC FATHATAN..ARABIC HAMZA BELOW 0670 ; Inherited # Mn ARABIC LETTER SUPERSCRIPT ALEF 0951..0952 ; Inherited # Mn [2] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI STRESS SIGN ANUDATTA +1AB0..1ABD ; Inherited # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW +1ABE ; Inherited # Me COMBINING PARENTHESES OVERLAY 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 1CED ; Inherited # Mn VEDIC SIGN TIRYAK 1CF4 ; Inherited # Mn VEDIC TONE CANDRA ABOVE -1DC0..1DE6 ; Inherited # Mn [39] COMBINING DOTTED GRAVE ACCENT..COMBINING LATIN SMALL LETTER Z +1CF8..1CF9 ; Inherited # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE +1DC0..1DF5 ; Inherited # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE 1DFC..1DFF ; Inherited # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 200C..200D ; Inherited # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER 20D0..20DC ; Inherited # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE @@ -1495,15 +1539,16 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE 302A..302D ; Inherited # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK 3099..309A ; Inherited # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK FE00..FE0F ; Inherited # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 -FE20..FE26 ; Inherited # Mn [7] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON +FE20..FE2D ; Inherited # Mn [14] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON BELOW 101FD ; Inherited # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE +102E0 ; Inherited # Mn COPTIC EPACT THOUSANDS MARK 1D167..1D169 ; Inherited # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 1D17B..1D182 ; Inherited # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE 1D185..1D18B ; Inherited # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE 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: 523 +# Total code points: 563 # ================================================ @@ -1537,7 +1582,7 @@ E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-2 # ================================================ -1900..191C ; Limbu # Lo [29] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER HA +1900..191E ; Limbu # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA 1920..1922 ; Limbu # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U 1923..1926 ; Limbu # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU 1927..1928 ; Limbu # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O @@ -1550,7 +1595,7 @@ E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-2 1944..1945 ; Limbu # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK 1946..194F ; Limbu # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE -# Total code points: 66 +# Total code points: 68 # ================================================ @@ -1612,7 +1657,8 @@ E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-2 1A00..1A16 ; Buginese # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA 1A17..1A18 ; Buginese # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U -1A19..1A1B ; Buginese # Mc [3] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN AE +1A19..1A1A ; Buginese # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O +1A1B ; Buginese # Mn BUGINESE VOWEL SIGN AE 1A1E..1A1F ; Buginese # Po [2] BUGINESE PALLAWA..BUGINESE END OF SECTION # Total code points: 30 @@ -1724,11 +1770,11 @@ A828..A82B ; Syloti_Nagri # So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI # ================================================ -12000..1236E ; Cuneiform # Lo [879] CUNEIFORM SIGN A..CUNEIFORM SIGN ZUM -12400..12462 ; Cuneiform # Nl [99] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER -12470..12473 ; Cuneiform # Po [4] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON +12000..12398 ; Cuneiform # Lo [921] CUNEIFORM SIGN A..CUNEIFORM SIGN UM TIMES ME +12400..1246E ; Cuneiform # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM +12470..12474 ; Cuneiform # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON -# Total code points: 982 +# Total code points: 1037 # ================================================ @@ -1767,8 +1813,7 @@ A874..A877 ; Phags_Pa # Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOU 1BA6..1BA7 ; Sundanese # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG 1BA8..1BA9 ; Sundanese # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG 1BAA ; Sundanese # Mc SUNDANESE SIGN PAMAAEH -1BAB ; Sundanese # Mn SUNDANESE SIGN VIRAMA -1BAC..1BAD ; Sundanese # Mc [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA +1BAB..1BAD ; Sundanese # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA 1BAE..1BAF ; Sundanese # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA 1BB0..1BB9 ; Sundanese # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE 1BBA..1BBF ; Sundanese # Lo [6] SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M @@ -1825,9 +1870,9 @@ A8D0..A8D9 ; Saurashtra # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NI A900..A909 ; Kayah_Li # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE A90A..A925 ; Kayah_Li # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO A926..A92D ; Kayah_Li # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU -A92E..A92F ; Kayah_Li # Po [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA +A92F ; Kayah_Li # Po KAYAH LI SIGN SHYA -# Total code points: 48 +# Total code points: 47 # ================================================ @@ -1974,11 +2019,10 @@ A9BA..A9BB ; Javanese # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL S A9BC ; Javanese # Mn JAVANESE VOWEL SIGN PEPET A9BD..A9C0 ; Javanese # Mc [4] JAVANESE CONSONANT SIGN KERET..JAVANESE PANGKON A9C1..A9CD ; Javanese # Po [13] JAVANESE LEFT RERENGGAN..JAVANESE TURNED PADA PISELEH -A9CF ; Javanese # Lm JAVANESE PANGRANGKEP A9D0..A9D9 ; Javanese # Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE A9DE..A9DF ; Javanese # Po [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN -# Total code points: 91 +# Total code points: 90 # ================================================ @@ -2080,8 +2124,9 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI 11047..1104D ; Brahmi # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS 11052..11065 ; Brahmi # No [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND 11066..1106F ; Brahmi # Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE +1107F ; Brahmi # Mn BRAHMI NUMBER JOINER -# Total code points: 108 +# Total code points: 109 # ================================================ @@ -2136,9 +2181,11 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI 111BF..111C0 ; Sharada # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA 111C1..111C4 ; Sharada # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM 111C5..111C8 ; Sharada # Po [4] SHARADA DANDA..SHARADA SEPARATOR +111CD ; Sharada # Po SHARADA SUTRA MARK 111D0..111D9 ; Sharada # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE +111DA ; Sharada # Lo SHARADA EKAM -# Total code points: 83 +# Total code points: 85 # ================================================ @@ -2161,4 +2208,244 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI # Total code points: 66 +# ================================================ + +10530..10563 ; Caucasian_Albanian # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW +1056F ; Caucasian_Albanian # Po CAUCASIAN ALBANIAN CITATION MARK + +# Total code points: 53 + +# ================================================ + +16AD0..16AED ; Bassa_Vah # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I +16AF0..16AF4 ; Bassa_Vah # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE +16AF5 ; Bassa_Vah # Po BASSA VAH FULL STOP + +# Total code points: 36 + +# ================================================ + +1BC00..1BC6A ; Duployan # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M +1BC70..1BC7C ; Duployan # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK +1BC80..1BC88 ; Duployan # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL +1BC90..1BC99 ; Duployan # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW +1BC9C ; Duployan # So DUPLOYAN SIGN O WITH CROSS +1BC9D..1BC9E ; Duployan # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1BC9F ; Duployan # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP + +# Total code points: 143 + +# ================================================ + +10500..10527 ; Elbasan # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE + +# Total code points: 40 + +# ================================================ + +11301 ; Grantha # Mn GRANTHA SIGN CANDRABINDU +11302..11303 ; Grantha # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA +11305..1130C ; Grantha # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L +1130F..11310 ; Grantha # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI +11313..11328 ; Grantha # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA +1132A..11330 ; Grantha # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA +11332..11333 ; Grantha # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA +11335..11339 ; Grantha # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA +1133C ; Grantha # Mn GRANTHA SIGN NUKTA +1133D ; Grantha # Lo GRANTHA SIGN AVAGRAHA +1133E..1133F ; Grantha # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I +11340 ; Grantha # Mn GRANTHA VOWEL SIGN II +11341..11344 ; Grantha # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR +11347..11348 ; Grantha # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI +1134B..1134D ; Grantha # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA +11357 ; Grantha # Mc GRANTHA AU LENGTH MARK +1135D..11361 ; Grantha # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11362..11363 ; Grantha # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +11366..1136C ; Grantha # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX +11370..11374 ; Grantha # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA + +# Total code points: 83 + +# ================================================ + +16B00..16B2F ; Pahawh_Hmong # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU +16B30..16B36 ; Pahawh_Hmong # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM +16B37..16B3B ; Pahawh_Hmong # Po [5] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS FEEM +16B3C..16B3F ; Pahawh_Hmong # So [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB +16B40..16B43 ; Pahawh_Hmong # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM +16B44 ; Pahawh_Hmong # Po PAHAWH HMONG SIGN XAUS +16B45 ; Pahawh_Hmong # So PAHAWH HMONG SIGN CIM TSOV ROG +16B50..16B59 ; Pahawh_Hmong # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE +16B5B..16B61 ; Pahawh_Hmong # No [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS +16B63..16B77 ; Pahawh_Hmong # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS +16B7D..16B8F ; Pahawh_Hmong # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ + +# Total code points: 127 + +# ================================================ + +11200..11211 ; Khojki # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA +11213..1122B ; Khojki # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA +1122C..1122E ; Khojki # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II +1122F..11231 ; Khojki # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI +11232..11233 ; Khojki # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU +11234 ; Khojki # Mn KHOJKI SIGN ANUSVARA +11235 ; Khojki # Mc KHOJKI SIGN VIRAMA +11236..11237 ; Khojki # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA +11238..1123D ; Khojki # Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN + +# Total code points: 61 + +# ================================================ + +10600..10736 ; Linear_A # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 +10740..10755 ; Linear_A # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE +10760..10767 ; Linear_A # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 + +# Total code points: 341 + +# ================================================ + +11150..11172 ; Mahajani # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA +11173 ; Mahajani # Mn MAHAJANI SIGN NUKTA +11174..11175 ; Mahajani # Po [2] MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK +11176 ; Mahajani # Lo MAHAJANI LIGATURE SHRI + +# Total code points: 39 + +# ================================================ + +10AC0..10AC7 ; Manichaean # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW +10AC8 ; Manichaean # So MANICHAEAN SIGN UD +10AC9..10AE4 ; Manichaean # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW +10AE5..10AE6 ; Manichaean # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW +10AEB..10AEF ; Manichaean # No [5] MANICHAEAN NUMBER ONE..MANICHAEAN NUMBER ONE HUNDRED +10AF0..10AF6 ; Manichaean # Po [7] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION LINE FILLER + +# Total code points: 51 + +# ================================================ + +1E800..1E8C4 ; Mende_Kikakui # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON +1E8C7..1E8CF ; Mende_Kikakui # No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE +1E8D0..1E8D6 ; Mende_Kikakui # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS + +# Total code points: 213 + +# ================================================ + +11600..1162F ; Modi # Lo [48] MODI LETTER A..MODI LETTER LLA +11630..11632 ; Modi # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II +11633..1163A ; Modi # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI +1163B..1163C ; Modi # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU +1163D ; Modi # Mn MODI SIGN ANUSVARA +1163E ; Modi # Mc MODI SIGN VISARGA +1163F..11640 ; Modi # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA +11641..11643 ; Modi # Po [3] MODI DANDA..MODI ABBREVIATION SIGN +11644 ; Modi # Lo MODI SIGN HUVA +11650..11659 ; Modi # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE + +# Total code points: 79 + +# ================================================ + +16A40..16A5E ; Mro # Lo [31] MRO LETTER TA..MRO LETTER TEK +16A60..16A69 ; Mro # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE +16A6E..16A6F ; Mro # Po [2] MRO DANDA..MRO DOUBLE DANDA + +# Total code points: 43 + +# ================================================ + +10A80..10A9C ; Old_North_Arabian # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH +10A9D..10A9F ; Old_North_Arabian # No [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY + +# Total code points: 32 + +# ================================================ + +10880..1089E ; Nabataean # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW +108A7..108AF ; Nabataean # No [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED + +# Total code points: 40 + +# ================================================ + +10860..10876 ; Palmyrene # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW +10877..10878 ; Palmyrene # So [2] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE RIGHT-POINTING FLEURON +10879..1087F ; Palmyrene # No [7] PALMYRENE NUMBER ONE..PALMYRENE NUMBER TWENTY + +# Total code points: 32 + +# ================================================ + +11AC0..11AF8 ; Pau_Cin_Hau # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL + +# Total code points: 57 + +# ================================================ + +10350..10375 ; Old_Permic # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA +10376..1037A ; Old_Permic # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII + +# Total code points: 43 + +# ================================================ + +10B80..10B91 ; Psalter_Pahlavi # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW +10B99..10B9C ; Psalter_Pahlavi # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT +10BA9..10BAF ; Psalter_Pahlavi # No [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED + +# Total code points: 29 + +# ================================================ + +11580..115AE ; Siddham # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA +115AF..115B1 ; Siddham # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II +115B2..115B5 ; Siddham # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR +115B8..115BB ; Siddham # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU +115BC..115BD ; Siddham # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA +115BE ; Siddham # Mc SIDDHAM SIGN VISARGA +115BF..115C0 ; Siddham # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA +115C1..115C9 ; Siddham # Po [9] SIDDHAM SIGN SIDDHAM..SIDDHAM END OF TEXT MARK + +# Total code points: 72 + +# ================================================ + +112B0..112DE ; Khudawadi # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA +112DF ; Khudawadi # Mn KHUDAWADI SIGN ANUSVARA +112E0..112E2 ; Khudawadi # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II +112E3..112EA ; Khudawadi # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA +112F0..112F9 ; Khudawadi # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE + +# Total code points: 69 + +# ================================================ + +11480..114AF ; Tirhuta # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA +114B0..114B2 ; Tirhuta # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II +114B3..114B8 ; Tirhuta # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL +114B9 ; Tirhuta # Mc TIRHUTA VOWEL SIGN E +114BA ; Tirhuta # Mn TIRHUTA VOWEL SIGN SHORT E +114BB..114BE ; Tirhuta # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU +114BF..114C0 ; Tirhuta # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA +114C1 ; Tirhuta # Mc TIRHUTA SIGN VISARGA +114C2..114C3 ; Tirhuta # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA +114C4..114C5 ; Tirhuta # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG +114C6 ; Tirhuta # Po TIRHUTA ABBREVIATION SIGN +114C7 ; Tirhuta # Lo TIRHUTA OM +114D0..114D9 ; Tirhuta # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE + +# Total code points: 82 + +# ================================================ + +118A0..118DF ; Warang_Citi # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO +118E0..118E9 ; Warang_Citi # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE +118EA..118F2 ; Warang_Citi # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY +118FF ; Warang_Citi # Lo WARANG CITI OM + +# Total code points: 84 + # EOF diff --git a/jdk/test/java/text/Bidi/BidiConformance.java b/jdk/test/java/text/Bidi/BidiConformance.java index 5485a050f07..73689659cc3 100644 --- a/jdk/test/java/text/Bidi/BidiConformance.java +++ b/jdk/test/java/text/Bidi/BidiConformance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 6850113 + * @bug 6850113 8032446 * @summary confirm the behavior of new Bidi implementation. (Backward compatibility) */ @@ -40,6 +40,8 @@ public class BidiConformance { private static boolean verbose = false; private static boolean abort = false; + private static final byte MAX_EXPLICIT_LEVEL = 125; + public static void main(String[] args) { for (int i = 0; i < args.length; i++) { String arg = args[i]; @@ -368,15 +370,15 @@ public class BidiConformance { AttributedString astr = new AttributedString(paragraph); astr.addAttribute(TextAttribute.RUN_DIRECTION, TextAttribute.RUN_DIRECTION_RTL); - astr.addAttribute(TextAttribute.BIDI_EMBEDDING, new Integer(-61), + astr.addAttribute(TextAttribute.BIDI_EMBEDDING, new Integer(-MAX_EXPLICIT_LEVEL), start, limit); try { bidi = new Bidi(astr.getIterator()); for (int i = start; i < limit; i++) { - if (bidi.getLevelAt(i) != 61) { + if (bidi.getLevelAt(i) != MAX_EXPLICIT_LEVEL) { errorHandling("Bidi(AttributedCharacterIterator).getLevelAt(" + i + ") should not be " + bidi.getLevelAt(i) + - " but 60 when BIDI_EMBEDDING is -61."); + " but MAX_EXPLICIT_LEVEL-1 when BIDI_EMBEDDING is -MAX_EXPLICIT_LEVEL."); } } } @@ -387,14 +389,14 @@ public class BidiConformance { astr = new AttributedString(paragraph); astr.addAttribute(TextAttribute.RUN_DIRECTION, TextAttribute.RUN_DIRECTION_RTL); - astr.addAttribute(TextAttribute.BIDI_EMBEDDING, new Integer(-62), + astr.addAttribute(TextAttribute.BIDI_EMBEDDING, new Integer(-(MAX_EXPLICIT_LEVEL+1)), start, limit); try { bidi = new Bidi(astr.getIterator()); for (int i = start; i < limit; i++) { if (bidi.getLevelAt(i) != 1) { errorHandling("Bidi(AttributedCharacterIterator).getLevelAt() " + - "should be 1 when BIDI_EMBEDDING is -62."); + "should be 1 when BIDI_EMBEDDING is -(MAX_EXPLICIT_LEVEL+1)."); } } } @@ -405,14 +407,14 @@ public class BidiConformance { astr = new AttributedString(paragraph); astr.addAttribute(TextAttribute.RUN_DIRECTION, TextAttribute.RUN_DIRECTION_RTL); - astr.addAttribute(TextAttribute.BIDI_EMBEDDING, new Integer(60), + astr.addAttribute(TextAttribute.BIDI_EMBEDDING, new Integer(MAX_EXPLICIT_LEVEL-1), start, limit); try { bidi = new Bidi(astr.getIterator()); for (int i = start; i < limit; i++) { - if (bidi.getLevelAt(i) != 61) { + if (bidi.getLevelAt(i) != MAX_EXPLICIT_LEVEL) { errorHandling("Bidi(AttributedCharacterIterator).getLevelAt() " + - "should be 61 when BIDI_EMBEDDING is 60."); + "should be MAX_EXPLICIT_LEVEL when BIDI_EMBEDDING is MAX_EXPLICIT_LEVEL-1."); } } } @@ -423,15 +425,15 @@ public class BidiConformance { astr = new AttributedString(paragraph); astr.addAttribute(TextAttribute.RUN_DIRECTION, TextAttribute.RUN_DIRECTION_RTL); - astr.addAttribute(TextAttribute.BIDI_EMBEDDING, new Integer(61), + astr.addAttribute(TextAttribute.BIDI_EMBEDDING, new Integer(MAX_EXPLICIT_LEVEL), start, limit); try { bidi = new Bidi(astr.getIterator()); for (int i = start; i < limit; i++) { - if (bidi.getLevelAt(i) != 61) { + if (bidi.getLevelAt(i) != MAX_EXPLICIT_LEVEL) { errorHandling("Bidi(AttributedCharacterIterator).getLevelAt(" + i + ") should not be " + bidi.getLevelAt(i) + - " but 61 when BIDI_EMBEDDING is 61."); + " but MAX_EXPLICIT_LEVEL when BIDI_EMBEDDING is MAX_EXPLICIT_LEVEL."); } } } @@ -442,15 +444,15 @@ public class BidiConformance { astr = new AttributedString(paragraph); astr.addAttribute(TextAttribute.RUN_DIRECTION, TextAttribute.RUN_DIRECTION_RTL); - astr.addAttribute(TextAttribute.BIDI_EMBEDDING, new Integer(62), + astr.addAttribute(TextAttribute.BIDI_EMBEDDING, new Integer(MAX_EXPLICIT_LEVEL+1), start, limit); try { bidi = new Bidi(astr.getIterator()); for (int i = start; i < limit; i++) { if (bidi.getLevelAt(i) != 1) { - errorHandling("Bidi(AttributedCharacterIterator).getLevelAt()" + - " should not be " + bidi.getLevelAt(i) + - " but 1 when BIDI_EMBEDDING is 62."); + errorHandling("Bidi(AttributedCharacterIterator).getLevelAt(" + + i + ") should not be " + bidi.getLevelAt(i) + + " but 1 when BIDI_EMBEDDING is MAX_EXPLICIT_LEVEL+1."); } } } @@ -536,8 +538,8 @@ public class BidiConformance { } byte[] actualLevels = new byte[text.length]; - byte[] validEmbeddings1 = {0, -61, -60, -2, -1}; - byte[] expectedLevels1 = {0, 61, 60, 2, 1}; + byte[] validEmbeddings1 = {0, -MAX_EXPLICIT_LEVEL, -(MAX_EXPLICIT_LEVEL-1), -2, -1}; + byte[] expectedLevels1 = {0, MAX_EXPLICIT_LEVEL, MAX_EXPLICIT_LEVEL-1, 2, 1}; try { bidi = new Bidi(text, 0, validEmbeddings1, 0, 5, Bidi.DIRECTION_LEFT_TO_RIGHT); @@ -553,11 +555,11 @@ public class BidiConformance { } catch (Exception e) { errorHandling("Bidi(char[], ...) should not throw an exception " + - "when embeddings is valid(-61)."); + "when embeddings is valid(-MAX_EXPLICIT_LEVEL)."); } - byte[] validEmbeddings2 = {0, 61, 60, 2, 1}; - byte[] expectedLevels2 = {0, 62, 60, 2, 2}; + byte[] validEmbeddings2 = {0, MAX_EXPLICIT_LEVEL, MAX_EXPLICIT_LEVEL-1, 2, 1}; + byte[] expectedLevels2 = {0, MAX_EXPLICIT_LEVEL+1, MAX_EXPLICIT_LEVEL-1, 2, 2}; try { bidi = new Bidi(text, 0, validEmbeddings2, 0, 5, Bidi.DIRECTION_LEFT_TO_RIGHT); @@ -573,35 +575,35 @@ public class BidiConformance { } catch (Exception e) { errorHandling("Bidi(char[], ...) should not throw an exception " + - "when embeddings is valid(61)."); + "when embeddings is valid(MAX_EXPLICIT_LEVEL)."); } - byte[] invalidEmbeddings1 = {0, -62, 0, 0, 0}; + byte[] invalidEmbeddings1 = {0, -(MAX_EXPLICIT_LEVEL+1), 0, 0, 0}; try { bidi = new Bidi(text, 0, invalidEmbeddings1, 0, 5, Bidi.DIRECTION_LEFT_TO_RIGHT); if (bidi.getLevelAt(1) != 0) { errorHandling("Bidi(char[], ...).getLevelAt(1) should be 0 " + - "when embeddings[1] is -62."); + "when embeddings[1] is -(MAX_EXPLICIT_LEVEL+1)."); } } catch (Exception e) { errorHandling("Bidi(char[], ...) should not throw an exception " + - "even when embeddings includes -62."); + "even when embeddings includes -(MAX_EXPLICIT_LEVEL+1)."); } - byte[] invalidEmbeddings2 = {0, 62, 0, 0, 0}; + byte[] invalidEmbeddings2 = {0, MAX_EXPLICIT_LEVEL+1, 0, 0, 0}; try { bidi = new Bidi(text, 0, invalidEmbeddings2, 0, 5, Bidi.DIRECTION_LEFT_TO_RIGHT); if (bidi.getLevelAt(1) != 0) { errorHandling("Bidi(char[], ...).getLevelAt(1) should be 0 " + - "when embeddings[1] is 62."); + "when embeddings[1] is MAX_EXPLICIT_LEVEL+1."); } } catch (Exception e) { errorHandling("Bidi(char[], ...) should not throw an exception " + - "even when embeddings includes 62."); + "even when embeddings includes MAX_EXPLICIT_LEVEL+1."); } try { @@ -1595,6 +1597,10 @@ public class BidiConformance { private static final char PDF = '\u202C'; private static final char LRO = '\u202D'; private static final char RLO = '\u202E'; + private static final char LRI = '\u2066'; + private static final char RLI = '\u2067'; + private static final char FSI = '\u2068'; + private static final char PDI = '\u2069'; /* * 0x05D0-0x05EA: [R] Hewbrew letters (Strong) @@ -2002,8 +2008,8 @@ public class BidiConformance { /* For Text #18 */ {" ABC (" + ArabicABC + " " + Arabic123 + ") 123.", - "0000001111222112220", "0000001111222112220", - "0000001111222112220", "1222111111222112221"}, + "0000001111222002220", "0000001111222002220", + "0000001111222002220", "1222111111222112221"}, /* For Text #19 */ {" " + HebrewABC + " (ABC 123) " + NKo123 + ".", @@ -2028,6 +2034,90 @@ public class BidiConformance { PDF, "22222221111111111111110", "22222221111111111111110", "22222221111111111111110", "44444443333333333333331"}, + + /* For Text #23 */ + {" ABC (" + Arabic123 + " " + ArabicABC + ") 123.", + "0000002221111002220", "0000002221111002220", + "0000002221111002220", "1222112221111112221"}, + + /* For Text #24 */ + {" 123 (" + ArabicABC + " " + Arabic123 + ") ABC.", + "1222111111222112221", "1222111111222112221", + "0000001111222000000", "1222111111222112221"}, + + /* For Text #25 */ + {" 123 (" + Arabic123 + " " + ArabicABC + ") ABC.", + "1222112221111112221", "1222112221111112221", + "0000002221111000000", "1222112221111112221"}, + + /* For Text #26 */ + {" " + ArabicABC + " (ABC 123) " + Arabic123 + ".", + "1111112222222112221", "1111112222222112221", + "0111000000000002220", "1111112222222112221"}, + + /* For Text #27 */ + {" " + ArabicABC + " (123 ABC) " + Arabic123 + ".", + "1111112221222112221", "1111112221222112221", + "0111002220000002220", "1111112221222112221"}, + + /* For Text #28 */ + {" " + Arabic123 + " (ABC 123) " + ArabicABC + ".", + "0222000000000001110", "0222000000000001110", + "0222000000000001110", "1222112222222111111"}, + + /* For Text #29 */ + {" " + Arabic123 + " (123 ABC) " + ArabicABC + ".", + "0222000000000001110", "0222000000000001110", + "0222000000000001110", "1222112221222111111"}, + + /* For Text #30 */ + {RLI + "ABC " + ArabicABC + " " + ArabicABC + "." + PDI, + "02221111111110", "14443333333331", + "02221111111110", "14443333333331"}, + + /* For Text #31 */ + {"ABC abc \"" + RLI + "IJK " + ArabicABC + " " + ArabicABC + PDI + + ".\" \"" + RLI + ArabicABC + " " + ArabicABC + PDI + ",\" xyz XYZ.", + "0000000000222111111110000001111111000000000000", + "0000000000222111111110000001111111000000000000", + "0000000000222111111110000001111111000000000000", + "2222222222444333333332222223333333222222222221"}, + + /* For Text #32 */ + {ArabicABC + " " + ArabicABC + " '" + LRI + "abc def \"" + RLI + + "xyz " + ArabicABC + " " + ArabicABC + PDI + "\"" + PDI + "'?", + "111111111122222222224443333333322111", + "111111111122222222224443333333322111", + "111111100022222222224443333333322000", + "111111111122222222224443333333322111"}, + + /* For Text #33 */ + {FSI + Arabic123 + " ABC " + ArabicABC + " " + ArabicABC + "." + PDI, + "044422222333333320", "144422222333333321", + "044422222333333320", "144422222333333321"}, + + /* For Text #34 */ + {FSI + "123 ABC " + ArabicABC + " " + ArabicABC + "." + PDI, + "022222222333333320", "122222222333333321", + "022222222333333320", "122222222333333321"}, + + /* For Text #35 */ + {FSI + "123 " + ArabicABC + " ABC " + ArabicABC + "." + PDI, + "022211111222111110", "144433333444333331", + "022211111222111110", "144433333444333331"}, + + /* For Text #36 */ + {FSI + Arabic123 + " " + ArabicABC + " ABC " + ArabicABC + "." + PDI, + "022211111222111110", "144433333444333331", + "022211111222111110", "144433333444333331"}, + + /* For Text #37 */ + {FSI + Arabic123 + " 123." + PDI, + "0444222220", "1444222221", "0444222220", "1444222221"}, + + /* For Text #38 */ + {FSI + "123 " + Arabic123 + "." + PDI, + "0222244420", "1222244421", "0222244420", "1222244421"}, }; /* Golden data for baseIsLeftToRight() results */ @@ -2060,10 +2150,32 @@ public class BidiConformance { {true, true, true, false}, {false, false, true, false}, - /* For Text #20 - $22 */ + /* For Text #20 - $24 */ {true, true, true, false}, {true, true, true, false}, {true, true, true, false}, + {true, true, true, false}, + {false, false, true, false}, + + /* For Text #25 - $29 */ + {false, false, true, false}, + {false, false, true, false}, + {false, false, true, false}, + {true, true, true, false}, + {true, true, true, false}, + + /* For Text #30 - $34 */ + {true, false, true, false}, + {true, true, true, false}, + {false, false, true, false}, + {true, false, true, false}, + {true , false, true, false}, + + /* For Text #35 - $38 */ + {true, false, true, false}, + {true, false, true, false}, + {true, false, true, false}, + {true, false, true, false}, }; /* Golden data for isLeftToRight() & isRightToLeft() results */ @@ -2097,7 +2209,29 @@ public class BidiConformance { {{false, false, false, false}, {false, false, false, false}}, {{false, false, false, false}, {false, false, false, false}}, - /* For Text #20 - $22 */ + /* For Text #20 - $24 */ + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + + /* For Text #25 - $29 */ + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + + /* For Text #30 - $34 */ + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + {{false, false, false, false}, {false, false, false, false}}, + + /* For Text #35 - $37 */ + {{false, false, false, false}, {false, false, false, false}}, {{false, false, false, false}, {false, false, false, false}}, {{false, false, false, false}, {false, false, false, false}}, {{false, false, false, false}, {false, false, false, false}}, @@ -2113,8 +2247,13 @@ public class BidiConformance { true, true, true, true, true, true, true, true, true, true, - /* For Text #20 - $22 */ - true, true, true, + /* For Text #20 - $29 */ + true, true, true, true, true, + true, true, true, true, true, + + /* For Text #30 - $37 */ + true, true, true, true, true, + true, true, true, true, }; /* --------------------------------------------------------------------- */ diff --git a/jdk/test/java/text/BreakIterator/Bug8032446.java b/jdk/test/java/text/BreakIterator/Bug8032446.java new file mode 100644 index 00000000000..4e5c0fbad39 --- /dev/null +++ b/jdk/test/java/text/BreakIterator/Bug8032446.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 8032446 + * @summary Confirm that BreakIterator works as expected with new characters in Unicode 7. + */ + +import java.text.*; +import java.util.*; + +public class Bug8032446 { + + public static void main(String[] args) { + boolean err = false; + + StringBuilder sb = new StringBuilder(); + for (int i = 0x10860; i <= 0x10876; i++) { // Palmyrene Letters + sb.append(Character.toChars(i)); + } + sb.append(" "); + for (int i = 0x10879; i <= 0x1087D; i++) { // Palmyrene Numbers + sb.append(Character.toChars(i)); + } + String s = sb.toString(); + + BreakIterator bi = BreakIterator.getWordInstance(Locale.ROOT); + bi.setText(s); + bi.first(); + + if (bi.next() != s.indexOf(' ')) { + throw new RuntimeException("Unexpected word breaking."); + } + } + +} diff --git a/jdk/test/sun/net/idn/NFS4StringPrep.java b/jdk/test/sun/net/idn/NFS4StringPrep.java index be1da5e192c..fc488f3957c 100644 --- a/jdk/test/sun/net/idn/NFS4StringPrep.java +++ b/jdk/test/sun/net/idn/NFS4StringPrep.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015 Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.text.ParseException; -import sun.text.normalizer.ICUData; import sun.net.idn.StringPrep; import sun.text.normalizer.UCharacterIterator;