Update #47 - Singleplayer lag fixes

This commit is contained in:
lax1dude
2025-01-19 13:26:27 -08:00
parent 3f5ee57068
commit 1f0d593a8c
2052 changed files with 133581 additions and 2339 deletions

View File

@ -0,0 +1,530 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* 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 jdk_internal.bidi.icu.impl;
import jdk_internal.bidi.icu.text.UnicodeSet.SpanCondition;
import jdk_internal.bidi.icu.util.OutputInt;
/**
* 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.
*/
public 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));
}
}

View File

@ -0,0 +1,175 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* 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) 1996-2014, International Business Machines Corporation and
* others. All Rights Reserved.
******************************************************************************
*/
package jdk_internal.bidi.icu.impl;
import java.io.DataInputStream;
import java.io.InputStream;
import jdk_internal.bidi.icu.text.UTF16;
import java.io.IOException;
/**
* Trie implementation which stores data in char, 16 bits.
*
* @author synwee
* @see com.ibm.icu.impl.Trie
* @since release 2.1, Jan 01 2002
*/
// note that i need to handle the block calculations later, since chartrie
// in icu4c uses the same index array.
public class CharTrie 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 CharTrie(InputStream inputStream, DataManipulate dataManipulate) throws IOException {
super(inputStream, dataManipulate);
if (!isCharTrie()) {
throw new IllegalArgumentException("Data given does not belong to a char 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
*/
public final char getCodePointValue(int ch) {
int offset;
// fastpath for U+0000..U+D7FF
if (0 <= ch && ch < UTF16.LEAD_SURROGATE_MIN_VALUE) {
// copy of getRawOffset()
offset = (m_index_[ch >> INDEX_STAGE_1_SHIFT_] << INDEX_STAGE_2_SHIFT_) + (ch & INDEX_STAGE_3_MASK_);
return m_data_[offset];
}
// handle U+D800..U+10FFFF
offset = getCodePointOffset(ch);
// return -1 if there is an error, in this case we return the default
// value: m_initialValue_
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
*/
public final char getLeadValue(char ch) {
return m_data_[getLeadOffset(ch)];
}
// 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 {
DataInputStream input = new DataInputStream(inputStream);
int indexDataLength = m_dataOffset_ + m_dataLength_;
m_index_ = new char[indexDataLength];
for (int i = 0; i < indexDataLength; i++) {
m_index_[i] = input.readChar();
}
m_data_ = m_index_;
m_initialValue_ = m_data_[m_dataOffset_];
}
/**
* 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;
}
// private data members --------------------------------------------
/**
* Default value
*/
private char m_initialValue_;
/**
* Array of char data
*/
private char m_data_[];
}

View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* 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 jdk_internal.bidi.icu.impl;
import jdk_internal.bidi.CharacterIterator;
import jdk_internal.bidi.icu.text.UCharacterIterator;
/**
* This class is a wrapper around CharacterIterator and implements the
* UCharacterIterator protocol
*
* @author ram
*/
public class CharacterIteratorWrapper extends UCharacterIterator {
private CharacterIterator iterator;
public CharacterIteratorWrapper(CharacterIterator iter) {
if (iter == null) {
throw new IllegalArgumentException();
}
iterator = iter;
}
/**
* @see UCharacterIterator#current()
*/
public int current() {
int c = iterator.current();
if (c == CharacterIterator.DONE) {
return DONE;
}
return c;
}
/**
* @see UCharacterIterator#getLength()
*/
public int getLength() {
return (iterator.getEndIndex() - iterator.getBeginIndex());
}
/**
* @see UCharacterIterator#getIndex()
*/
public int getIndex() {
return iterator.getIndex();
}
/**
* @see UCharacterIterator#next()
*/
public int next() {
int i = iterator.current();
iterator.next();
if (i == CharacterIterator.DONE) {
return DONE;
}
return i;
}
/**
* @see UCharacterIterator#previous()
*/
public int previous() {
int i = iterator.previous();
if (i == CharacterIterator.DONE) {
return DONE;
}
return i;
}
/**
* @see UCharacterIterator#setIndex(int)
*/
public void setIndex(int index) {
iterator.setIndex(index);
}
/**
* @see UCharacterIterator#getText(char[])
*/
public int getText(char[] fillIn, int offset) {
int length = iterator.getEndIndex() - iterator.getBeginIndex();
int currentIndex = iterator.getIndex();
if (offset < 0 || offset + length > fillIn.length) {
throw new IndexOutOfBoundsException(Integer.toString(length));
}
for (char ch = iterator.first(); ch != CharacterIterator.DONE; ch = iterator.next()) {
fillIn[offset++] = ch;
}
iterator.setIndex(currentIndex);
return length;
}
/**
* Creates a clone of this iterator. Clones the underlying character iterator.
*
* @see UCharacterIterator#clone()
*/
public Object clone() {
try {
CharacterIteratorWrapper result = (CharacterIteratorWrapper) super.clone();
result.iterator = (CharacterIterator) this.iterator.clone();
return result;
} catch (CloneNotSupportedException e) {
return null; // only invoked if bad underlying character iterator
}
}
}

View File

@ -0,0 +1,303 @@
/*
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* 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) 1996-2014, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
package jdk_internal.bidi.icu.impl;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import jdk_internal.bidi.icu.util.VersionInfo;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
public final class ICUBinary {
private static final class IsAcceptable implements Authenticate {
@Override
public boolean isDataVersionAcceptable(byte version[]) {
return version[0] == 1;
}
}
// public inner interface ------------------------------------------------
/**
* Special interface for data authentication
*/
public static interface Authenticate {
/**
* Method used in ICUBinary.readHeader() to provide data format authentication.
*
* @param version version of the current data
* @return true if dataformat is an acceptable version, false otherwise
*/
public boolean isDataVersionAcceptable(byte version[]);
}
// public methods --------------------------------------------------------
/**
* 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) {
try (InputStream is = EagRuntime.getRequiredResourceStream(itemPath)) {
// is.available() may return 0, or 1, or the total number of bytes in the
// stream,
// or some other number.
// Do not try to use is.available() == 0 to find the end of the stream!
byte[] bytes;
int avail = is.available();
if (avail > 32) {
// There are more bytes available than just the ICU data header length.
// With luck, it is the total number of bytes.
bytes = new byte[avail];
} else {
bytes = new byte[128]; // empty .res files are even smaller
}
// Call is.read(...) until one returns a negative value.
int length = 0;
for (;;) {
if (length < bytes.length) {
int numRead = is.read(bytes, length, bytes.length - length);
if (numRead < 0) {
break; // end of stream
}
length += numRead;
} else {
// See if we are at the end of the stream before we grow the array.
int nextByte = is.read();
if (nextByte < 0) {
break;
}
int capacity = 2 * bytes.length;
if (capacity < 128) {
capacity = 128;
} else if (capacity < 0x4000) {
capacity *= 2; // Grow faster until we reach 16kB.
}
bytes = Arrays.copyOf(bytes, capacity);
bytes[length++] = (byte) nextByte;
}
}
return ByteBuffer.wrap(bytes, 0, length);
} 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) throws IOException {
DataInputStream input = new DataInputStream(inputStream);
char headersize = input.readChar();
int readcount = 2;
// reading the header format
byte magic1 = input.readByte();
readcount++;
byte magic2 = input.readByte();
readcount++;
if (magic1 != MAGIC1 || magic2 != MAGIC2) {
throw new IOException(MAGIC_NUMBER_AUTHENTICATION_FAILED_);
}
input.readChar(); // reading size
readcount += 2;
input.readChar(); // reading reserved word
readcount += 2;
byte bigendian = input.readByte();
readcount++;
byte charset = input.readByte();
readcount++;
byte charsize = input.readByte();
readcount++;
input.readByte(); // reading reserved byte
readcount++;
byte dataFormatID[] = new byte[4];
input.readFully(dataFormatID);
readcount += 4;
byte dataVersion[] = new byte[4];
input.readFully(dataVersion);
readcount += 4;
byte unicodeVersion[] = new byte[4];
input.readFully(unicodeVersion);
readcount += 4;
if (headersize < readcount) {
throw new IOException("Internal Error: Header size error");
}
input.skipBytes(headersize - readcount);
if (bigendian != BIG_ENDIAN_ || charset != CHAR_SET_ || charsize != CHAR_SIZE_
|| !Arrays.equals(dataFormatIDExpected, dataFormatID)
|| (authenticate != null && !authenticate.isDataVersionAcceptable(dataVersion))) {
throw new IOException(HEADER_AUTHENTICATION_FAILED_);
}
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);
}
}
public static byte[] getBytes(ByteBuffer bytes, int length, int additionalSkipLength) {
byte[] dest = new byte[length];
bytes.get(dest);
if (additionalSkipLength > 0) {
skipBytes(bytes, additionalSkipLength);
}
return dest;
}
public static String getString(ByteBuffer bytes, int length, int additionalSkipLength) {
CharSequence cs = bytes.asCharBuffer();
String s = cs.subSequence(0, length).toString();
skipBytes(bytes, length * 2 + additionalSkipLength);
return s;
}
public static char[] getChars(ByteBuffer bytes, int length, int additionalSkipLength) {
char[] dest = new char[length];
bytes.asCharBuffer().get(dest);
skipBytes(bytes, length * 2 + additionalSkipLength);
return dest;
}
public static int[] getInts(ByteBuffer bytes, int length, int additionalSkipLength) {
int[] dest = new int[length];
bytes.asIntBuffer().get(dest);
skipBytes(bytes, length * 4 + additionalSkipLength);
return dest;
}
/**
* 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 -------------------------------------------------
/**
* Magic numbers to authenticate the data file
*/
private static final byte MAGIC1 = (byte) 0xda;
private static final byte MAGIC2 = (byte) 0x27;
/**
* File format authentication values
*/
private static final byte CHAR_SET_ = 0;
private static final byte CHAR_SIZE_ = 2;
/**
* Error messages
*/
private static final String MAGIC_NUMBER_AUTHENTICATION_FAILED_ = "ICUBinary data file error: Magic number authentication failed";
private static final String HEADER_AUTHENTICATION_FAILED_ = "ICUBinary data file error: Header authentication failed";
}

View File

@ -0,0 +1,296 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* 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 jdk_internal.bidi.icu.impl;
import java.io.IOException;
import jdk_internal.bidi.icu.text.Normalizer2;
public 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 abstract static 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.hasDecompBoundaryBefore(c);
}
}
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 {
@SuppressWarnings("deprecation")
String DATA_FILE_NAME = "/assets/eagler/icudt/" + name + ".nrm";
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");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,500 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* 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) 2003-2004, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
//
// CHANGELOG
// 2005-05-19 Edward Wang
// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/text/Punycode.java
// - move from package com.ibm.icu.text to package sun.net.idn
// - use ParseException instead of StringPrepParseException
// 2007-08-14 Martin Buchholz
// - remove redundant casts
//
package jdk_internal.bidi.icu.impl;
import java.text.ParseException;
import jdk_internal.bidi.icu.lang.UCharacter;
import jdk_internal.bidi.icu.text.UTF16;
/**
* Ported code from ICU punycode.c
*
* @author ram
*/
/* Package Private class */
public final class Punycode {
/* Punycode parameters for Bootstring */
private static final int BASE = 36;
private static final int TMIN = 1;
private static final int TMAX = 26;
private static final int SKEW = 38;
private static final int DAMP = 700;
private static final int INITIAL_BIAS = 72;
private static final int INITIAL_N = 0x80;
/* "Basic" Unicode/ASCII code points */
private static final int HYPHEN = 0x2d;
private static final int DELIMITER = HYPHEN;
private static final int ZERO = 0x30;
private static final int NINE = 0x39;
private static final int SMALL_A = 0x61;
private static final int SMALL_Z = 0x7a;
private static final int CAPITAL_A = 0x41;
private static final int CAPITAL_Z = 0x5a;
// TODO: eliminate the 256 limitation
private static final int MAX_CP_COUNT = 256;
private static final int UINT_MAGIC = 0x80000000;
private static final long ULONG_MAGIC = 0x8000000000000000L;
private static int adaptBias(int delta, int length, boolean firstTime) {
if (firstTime) {
delta /= DAMP;
} else {
delta /= 2;
}
delta += delta / length;
int count = 0;
for (; delta > ((BASE - TMIN) * TMAX) / 2; count += BASE) {
delta /= (BASE - TMIN);
}
return count + (((BASE - TMIN + 1) * delta) / (delta + SKEW));
}
/**
* basicToDigit[] contains the numeric value of a basic code point (for use in
* representing integers) in the range 0 to BASE-1, or -1 if b is does not
* represent a value.
*/
static final int[] basicToDigit = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1,
-1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1,
-1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1,
-1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1 };
private static char asciiCaseMap(char b, boolean uppercase) {
if (uppercase) {
if (SMALL_A <= b && b <= SMALL_Z) {
b -= (SMALL_A - CAPITAL_A);
}
} else {
if (CAPITAL_A <= b && b <= CAPITAL_Z) {
b += (SMALL_A - CAPITAL_A);
}
}
return b;
}
/**
* digitToBasic() returns the basic code point whose value (when used for
* representing integers) is d, which must be in the range 0 to BASE-1. The
* lowercase form is used unless the uppercase flag is nonzero, in which case
* the uppercase form is used.
*/
private static char digitToBasic(int digit, boolean uppercase) {
/* 0..25 map to ASCII a..z or A..Z */
/* 26..35 map to ASCII 0..9 */
if (digit < 26) {
if (uppercase) {
return (char) (CAPITAL_A + digit);
} else {
return (char) (SMALL_A + digit);
}
} else {
return (char) ((ZERO - 26) + digit);
}
}
/**
* Converts Unicode to Punycode. The input string must not contain single,
* unpaired surrogates. The output will be represented as an array of ASCII code
* points.
*
* @param src
* @param caseFlags
* @return
* @throws ParseException
*/
public static StringBuffer encode(StringBuffer src, boolean[] caseFlags) throws ParseException {
int[] cpBuffer = new int[MAX_CP_COUNT];
int n, delta, handledCPCount, basicLength, destLength, bias, j, m, q, k, t, srcCPCount;
char c, c2;
int srcLength = src.length();
int destCapacity = MAX_CP_COUNT;
char[] dest = new char[destCapacity];
StringBuffer result = new StringBuffer();
/*
* Handle the basic code points and convert extended ones to UTF-32 in cpBuffer
* (caseFlag in sign bit):
*/
srcCPCount = destLength = 0;
for (j = 0; j < srcLength; ++j) {
if (srcCPCount == MAX_CP_COUNT) {
/* too many input code points */
throw new ParseException("Too many input code points", -1);
}
c = src.charAt(j);
if (isBasic(c)) {
if (destLength < destCapacity) {
cpBuffer[srcCPCount++] = 0;
dest[destLength] = caseFlags != null ? asciiCaseMap(c, caseFlags[j]) : c;
}
++destLength;
} else {
n = ((caseFlags != null && caseFlags[j]) ? 1 : 0) << 31L;
if (!UTF16.isSurrogate(c)) {
n |= c;
} else if (UTF16.isLeadSurrogate(c) && (j + 1) < srcLength
&& UTF16.isTrailSurrogate(c2 = src.charAt(j + 1))) {
++j;
n |= UCharacter.getCodePoint(c, c2);
} else {
/* error: unmatched surrogate */
throw new ParseException("Illegal char found", -1);
}
cpBuffer[srcCPCount++] = n;
}
}
/* Finish the basic string - if it is not empty - with a delimiter. */
basicLength = destLength;
if (basicLength > 0) {
if (destLength < destCapacity) {
dest[destLength] = DELIMITER;
}
++destLength;
}
/*
* handledCPCount is the number of code points that have been handled
* basicLength is the number of basic code points destLength is the number of
* chars that have been output
*/
/* Initialize the state: */
n = INITIAL_N;
delta = 0;
bias = INITIAL_BIAS;
/* Main encoding loop: */
for (handledCPCount = basicLength; handledCPCount < srcCPCount; /* no op */) {
/*
* All non-basic code points < n have been handled already. Find the next larger
* one:
*/
for (m = 0x7fffffff, j = 0; j < srcCPCount; ++j) {
q = cpBuffer[j] & 0x7fffffff; /* remove case flag from the sign bit */
if (n <= q && q < m) {
m = q;
}
}
/*
* Increase delta enough to advance the decoder's <n,i> state to <m,0>, but
* guard against overflow:
*/
if (m - n > (0x7fffffff - MAX_CP_COUNT - delta) / (handledCPCount + 1)) {
throw new RuntimeException("Internal program error");
}
delta += (m - n) * (handledCPCount + 1);
n = m;
/* Encode a sequence of same code points n */
for (j = 0; j < srcCPCount; ++j) {
q = cpBuffer[j] & 0x7fffffff; /* remove case flag from the sign bit */
if (q < n) {
++delta;
} else if (q == n) {
/* Represent delta as a generalized variable-length integer: */
for (q = delta, k = BASE; /* no condition */; k += BASE) {
/**
* RAM: comment out the old code for conformance with
* draft-ietf-idn-punycode-03.txt
*
* t=k-bias; if(t<TMIN) { t=TMIN; } else if(t>TMAX) { t=TMAX; }
*/
t = k - bias;
if (t < TMIN) {
t = TMIN;
} else if (k >= (bias + TMAX)) {
t = TMAX;
}
if (q < t) {
break;
}
if (destLength < destCapacity) {
dest[destLength++] = digitToBasic(t + (q - t) % (BASE - t), false);
}
q = (q - t) / (BASE - t);
}
if (destLength < destCapacity) {
dest[destLength++] = digitToBasic(q, (cpBuffer[j] < 0));
}
bias = adaptBias(delta, handledCPCount + 1, (handledCPCount == basicLength));
delta = 0;
++handledCPCount;
}
}
++delta;
++n;
}
return result.append(dest, 0, destLength);
}
private static boolean isBasic(int ch) {
return (ch < INITIAL_N);
}
private static boolean isBasicUpperCase(int ch) {
return (CAPITAL_A <= ch && ch <= CAPITAL_Z);
}
private static boolean isSurrogate(int ch) {
return (((ch) & 0xfffff800) == 0xd800);
}
/**
* Converts Punycode to Unicode. The Unicode string will be at most as long as
* the Punycode string.
*
* @param src
* @param caseFlags
* @return
* @throws ParseException
*/
public static StringBuffer decode(StringBuffer src, boolean[] caseFlags) throws ParseException {
int srcLength = src.length();
StringBuffer result = new StringBuffer();
int n, destLength, i, bias, basicLength, j, in, oldi, w, k, digit, t, destCPCount, firstSupplementaryIndex,
cpLength;
char b;
int destCapacity = MAX_CP_COUNT;
char[] dest = new char[destCapacity];
/*
* Handle the basic code points: Let basicLength be the number of input code
* points before the last delimiter, or 0 if there is none, then copy the first
* basicLength code points to the output.
*
* The two following loops iterate backward.
*/
for (j = srcLength; j > 0;) {
if (src.charAt(--j) == DELIMITER) {
break;
}
}
destLength = basicLength = destCPCount = j;
while (j > 0) {
b = src.charAt(--j);
if (!isBasic(b)) {
throw new ParseException("Illegal char found", -1);
}
if (j < destCapacity) {
dest[j] = b;
if (caseFlags != null) {
caseFlags[j] = isBasicUpperCase(b);
}
}
}
/* Initialize the state: */
n = INITIAL_N;
i = 0;
bias = INITIAL_BIAS;
firstSupplementaryIndex = 1000000000;
/*
* Main decoding loop: Start just after the last delimiter if any basic code
* points were copied; start at the beginning otherwise.
*/
for (in = basicLength > 0 ? basicLength + 1 : 0; in < srcLength; /* no op */) {
/*
* in is the index of the next character to be consumed, and destCPCount is the
* number of code points in the output array.
*
* Decode a generalized variable-length integer into delta, which gets added to
* i. The overflow checking is easier if we increase i as we go, then subtract
* off its starting value at the end to obtain delta.
*/
for (oldi = i, w = 1, k = BASE; /* no condition */; k += BASE) {
if (in >= srcLength) {
throw new ParseException("Illegal char found", -1);
}
digit = basicToDigit[(byte) src.charAt(in++)];
if (digit < 0) {
throw new ParseException("Invalid char found", -1);
}
if (digit > (0x7fffffff - i) / w) {
/* integer overflow */
throw new ParseException("Illegal char found", -1);
}
i += digit * w;
t = k - bias;
if (t < TMIN) {
t = TMIN;
} else if (k >= (bias + TMAX)) {
t = TMAX;
}
if (digit < t) {
break;
}
if (w > 0x7fffffff / (BASE - t)) {
/* integer overflow */
throw new ParseException("Illegal char found", -1);
}
w *= BASE - t;
}
/*
* Modification from sample code: Increments destCPCount here, where needed
* instead of in for() loop tail.
*/
++destCPCount;
bias = adaptBias(i - oldi, destCPCount, (oldi == 0));
/*
* i was supposed to wrap around from (incremented) destCPCount to 0,
* incrementing n each time, so we'll fix that now:
*/
if (i / destCPCount > (0x7fffffff - n)) {
/* integer overflow */
throw new ParseException("Illegal char found", -1);
}
n += i / destCPCount;
i %= destCPCount;
/* not needed for Punycode: */
/* if (decode_digit(n) <= BASE) return punycode_invalid_input; */
if (n > 0x10ffff || isSurrogate(n)) {
/* Unicode code point overflow */
throw new ParseException("Illegal char found", -1);
}
/* Insert n at position i of the output: */
cpLength = UTF16.getCharCount(n);
if ((destLength + cpLength) < destCapacity) {
int codeUnitIndex;
/*
* Handle indexes when supplementary code points are present.
*
* In almost all cases, there will be only BMP code points before i and even in
* the entire string. This is handled with the same efficiency as with UTF-32.
*
* Only the rare cases with supplementary code points are handled more slowly -
* but not too bad since this is an insertion anyway.
*/
if (i <= firstSupplementaryIndex) {
codeUnitIndex = i;
if (cpLength > 1) {
firstSupplementaryIndex = codeUnitIndex;
} else {
++firstSupplementaryIndex;
}
} else {
codeUnitIndex = firstSupplementaryIndex;
codeUnitIndex = UTF16.moveCodePointOffset(dest, 0, destLength, codeUnitIndex, i - codeUnitIndex);
}
/* use the UChar index codeUnitIndex instead of the code point index i */
if (codeUnitIndex < destLength) {
System.arraycopy(dest, codeUnitIndex, dest, codeUnitIndex + cpLength, (destLength - codeUnitIndex));
if (caseFlags != null) {
System.arraycopy(caseFlags, codeUnitIndex, caseFlags, codeUnitIndex + cpLength,
destLength - codeUnitIndex);
}
}
if (cpLength == 1) {
/* BMP, insert one code unit */
dest[codeUnitIndex] = (char) n;
} else {
/* supplementary character, insert two code units */
dest[codeUnitIndex] = UTF16.getLeadSurrogate(n);
dest[codeUnitIndex + 1] = UTF16.getTrailSurrogate(n);
}
if (caseFlags != null) {
/* Case of last character determines uppercase flag: */
caseFlags[codeUnitIndex] = isBasicUpperCase(src.charAt(in - 1));
if (cpLength == 2) {
caseFlags[codeUnitIndex + 1] = false;
}
}
}
destLength += cpLength;
++i;
}
result.append(dest, 0, destLength);
return result;
}
}

View File

@ -0,0 +1,198 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* 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 jdk_internal.bidi.icu.impl;
import jdk_internal.bidi.icu.text.Replaceable;
import jdk_internal.bidi.icu.text.ReplaceableString;
import jdk_internal.bidi.icu.text.UCharacterIterator;
/**
* DLF docs must define behavior when Replaceable is mutated underneath the
* iterator.
*
* This and ICUCharacterIterator share some code, maybe they should share an
* implementation, or the common state and implementation should be moved up
* into UCharacterIterator.
*
* What are first, last, and getBeginIndex doing here?!?!?!
*/
public class ReplaceableUCharacterIterator extends UCharacterIterator {
// public constructor ------------------------------------------------------
/**
* Public constructor
*
* @param str text which the iterator will be based on
*/
public ReplaceableUCharacterIterator(String str) {
if (str == null) {
throw new IllegalArgumentException();
}
this.replaceable = new ReplaceableString(str);
this.currentIndex = 0;
}
/**
* Public constructor
*
* @param buf buffer of text on which the iterator will be based
*/
public ReplaceableUCharacterIterator(StringBuffer buf) {
if (buf == null) {
throw new IllegalArgumentException();
}
this.replaceable = new ReplaceableString(buf);
this.currentIndex = 0;
}
// public methods ----------------------------------------------------------
/**
* Creates a copy of this iterator, does not clone the underlying
* <code>Replaceable</code>object
*
* @return copy of this iterator
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null; // never invoked
}
}
/**
* Returns the current UTF16 character.
*
* @return current UTF16 character
*/
public int current() {
if (currentIndex < replaceable.length()) {
return replaceable.charAt(currentIndex);
}
return DONE;
}
/**
* Returns the length of the text
*
* @return length of the text
*/
public int getLength() {
return replaceable.length();
}
/**
* Gets the current currentIndex in text.
*
* @return current currentIndex in text.
*/
public int getIndex() {
return currentIndex;
}
/**
* Returns next UTF16 character and increments the iterator's currentIndex by 1.
* If the resulting currentIndex is greater or equal to the text length, the
* currentIndex is reset to the text length and a value of DONECODEPOINT is
* returned.
*
* @return next UTF16 character in text or DONE if the new currentIndex is off
* the end of the text range.
*/
public int next() {
if (currentIndex < replaceable.length()) {
return replaceable.charAt(currentIndex++);
}
return DONE;
}
/**
* Returns previous UTF16 character and decrements the iterator's currentIndex
* by 1. If the resulting currentIndex is less than 0, the currentIndex is reset
* to 0 and a value of DONECODEPOINT is returned.
*
* @return next UTF16 character in text or DONE if the new currentIndex is off
* the start of the text range.
*/
public int previous() {
if (currentIndex > 0) {
return replaceable.charAt(--currentIndex);
}
return DONE;
}
/**
* Sets the currentIndex to the specified currentIndex in the text and returns
* that single UTF16 character at currentIndex. This assumes the text is stored
* as 16-bit code units.
*
* @param currentIndex the currentIndex within the text.
* @exception IllegalArgumentException is thrown if an invalid currentIndex is
* supplied. i.e. currentIndex is out of
* bounds.
*/
public void setIndex(int currentIndex) {
if (currentIndex < 0 || currentIndex > replaceable.length()) {
throw new IllegalArgumentException();
}
this.currentIndex = currentIndex;
}
public int getText(char[] fillIn, int offset) {
int length = replaceable.length();
if (offset < 0 || offset + length > fillIn.length) {
throw new IndexOutOfBoundsException(Integer.toString(length));
}
replaceable.getChars(0, length, fillIn, offset);
return length;
}
// private data members ----------------------------------------------------
/**
* Replaceable object
*/
private Replaceable replaceable;
/**
* Current currentIndex
*/
private int currentIndex;
}

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* 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) 2003, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*
* Created on May 2, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
// CHANGELOG
// 2005-05-19 Edward Wang
// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/impl/StringPrepDataReader.java
// - move from package com.ibm.icu.impl to package sun.net.idn
//
package jdk_internal.bidi.icu.impl;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @author ram
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public final class StringPrepDataReader implements ICUBinary.Authenticate {
/**
* <p>
* private constructor.
* </p>
*
* @param inputStream ICU uprop.dat file input stream
* @exception IOException throw if data file fails authentication
* @draft 2.1
*/
public StringPrepDataReader(InputStream inputStream) throws IOException {
unicodeVersion = ICUBinary.readHeader(inputStream, DATA_FORMAT_ID, this);
dataInputStream = new DataInputStream(inputStream);
}
public void read(byte[] idnaBytes, char[] mappingTable) throws IOException {
// Read the bytes that make up the idnaTrie
dataInputStream.read(idnaBytes);
// Read the extra data
for (int i = 0; i < mappingTable.length; i++) {
mappingTable[i] = dataInputStream.readChar();
}
}
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 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;
}
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
*/
/// * dataFormat="SPRP" 0x53, 0x50, 0x52, 0x50 */
private static final byte DATA_FORMAT_ID[] = { (byte) 0x53, (byte) 0x50, (byte) 0x52, (byte) 0x50 };
private static final byte DATA_FORMAT_VERSION[] = { (byte) 0x3, (byte) 0x2, (byte) 0x5, (byte) 0x2 };
}

View File

@ -0,0 +1,368 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* 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) 1996-2014, International Business Machines Corporation and
* others. All Rights Reserved.
******************************************************************************
*/
package jdk_internal.bidi.icu.impl;
import java.io.DataInputStream;
import java.io.InputStream;
import jdk_internal.bidi.icu.lang.UCharacter;
import jdk_internal.bidi.icu.text.UTF16;
import java.io.IOException;
/**
* <p>
* A trie is a kind of compressed, serializable table of values associated with
* Unicode code points (0..0x10ffff).
* </p>
* <p>
* This class defines the basic structure of a trie and provides methods to
* <b>retrieve the offsets to the actual data</b>.
* </p>
* <p>
* Data will be the form of an array of basic types, char or int.
* </p>
* <p>
* The actual data format will have to be specified by the user in the inner
* static interface com.ibm.icu.impl.Trie.DataManipulate.
* </p>
* <p>
* This trie implementation is optimized for getting offset while walking
* forward through a UTF-16 string. Therefore, the simplest and fastest access
* macros are the fromLead() and fromOffsetTrail() methods. The fromBMP() method
* are a little more complicated; they get offsets even for lead surrogate
* codepoints, while the fromLead() method get special "folded" offsets for lead
* surrogate code units if there is relevant data associated with them. From
* such a folded offsets, an offset needs to be extracted to supply to the
* fromOffsetTrail() methods. To handle such supplementary codepoints, some
* offset information are kept in the data.
* </p>
* <p>
* Methods in com.ibm.icu.impl.Trie.DataManipulate are called to retrieve that
* offset from the folded value for the lead surrogate unit.
* </p>
* <p>
* For examples of use, see com.ibm.icu.impl.CharTrie or
* com.ibm.icu.impl.IntTrie.
* </p>
*
* @author synwee
* @see com.ibm.icu.impl.CharTrie
* @see com.ibm.icu.impl.IntTrie
* @since release 2.1, Jan 01 2002
*/
public abstract class Trie {
// public class declaration ----------------------------------------
/**
* Character data in com.ibm.impl.Trie have different user-specified format for
* different purposes. This interface specifies methods to be implemented in
* order for com.ibm.impl.Trie, to surrogate offset information encapsulated
* within the data.
*/
public static interface DataManipulate {
/**
* Called by com.ibm.icu.impl.Trie to extract from a lead surrogate's data the
* index array offset of the indexes for that lead surrogate.
*
* @param value 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
*/
public int getFoldingOffset(int value);
}
// default implementation
private static class DefaultGetFoldingOffset implements DataManipulate {
public int getFoldingOffset(int value) {
return value;
}
}
// protected constructor -------------------------------------------
/**
* Trie constructor for CharTrie use.
*
* @param inputStream ICU data file input stream which contains the trie
* @param dataManipulate object containing the information to parse the trie
* data
* @throws IOException thrown when input stream does not have the right header.
*/
protected Trie(InputStream inputStream, DataManipulate dataManipulate) throws IOException {
DataInputStream input = new DataInputStream(inputStream);
// Magic number to authenticate the data.
int signature = input.readInt();
m_options_ = input.readInt();
if (!checkHeader(signature)) {
throw new IllegalArgumentException(
"ICU data file error: Trie header authentication failed, please check if you have the most updated ICU data file");
}
if (dataManipulate != null) {
m_dataManipulate_ = dataManipulate;
} else {
m_dataManipulate_ = new DefaultGetFoldingOffset();
}
m_isLatin1Linear_ = (m_options_ & HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_) != 0;
m_dataOffset_ = input.readInt();
m_dataLength_ = input.readInt();
unserialize(inputStream);
}
// protected data members ------------------------------------------
/**
* 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
*/
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
*/
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;
/**
* Surrogate mask to use when shifting offset to retrieve supplementary values
*/
protected static final int SURROGATE_MASK_ = 0x3FF;
/**
* 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
*/
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.
*/
protected int m_dataOffset_;
/**
* Length of the data array
*/
protected int m_dataLength_;
// protected methods -----------------------------------------------
/**
* Gets the offset to the data which the surrogate pair points to.
*
* @param lead lead surrogate
* @param trail trailing surrogate
* @return offset to data
*/
protected abstract int getSurrogateOffset(char lead, char trail);
/**
* Gets the offset to the data which the index ch after variable offset points
* to. Note for locating a non-supplementary character data offset, calling
* <p>
* getRawOffset(0, ch);
* </p>
* will do. Otherwise if it is a supplementary character formed by surrogates
* lead and trail. Then we would have to call getRawOffset() with
* getFoldingIndexOffset(). See getSurrogateOffset().
*
* @param offset index offset which ch is to start from
* @param ch index to be used after offset
* @return offset to the data
*/
protected final int getRawOffset(int offset, char ch) {
return (m_index_[offset + (ch >> INDEX_STAGE_1_SHIFT_)] << INDEX_STAGE_2_SHIFT_) + (ch & INDEX_STAGE_3_MASK_);
}
/**
* Gets the offset to data which the BMP character points to Treats a lead
* surrogate as a normal code point.
*
* @param ch BMP character
* @return offset to data
*/
protected final int getBMPOffset(char ch) {
return (ch >= UTF16.LEAD_SURROGATE_MIN_VALUE && ch <= UTF16.LEAD_SURROGATE_MAX_VALUE)
? getRawOffset(LEAD_INDEX_OFFSET_, ch)
: getRawOffset(0, ch);
// using a getRawOffset(ch) makes no diff
}
/**
* Gets the offset to the data which this lead surrogate character points to.
* Data at the returned offset may contain folding offset information for the
* next trailing surrogate character.
*
* @param ch lead surrogate character
* @return offset to data
*/
protected final int getLeadOffset(char ch) {
return getRawOffset(0, ch);
}
/**
* 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
if (ch < 0) {
return -1;
} else if (ch < UTF16.LEAD_SURROGATE_MIN_VALUE) {
// fastpath for the part of the BMP below surrogates (D800) where getRawOffset()
// works
return getRawOffset(0, (char) ch);
} else if (ch < UTF16.SUPPLEMENTARY_MIN_VALUE) {
// BMP codepoint
return getBMPOffset((char) ch);
} else if (ch <= UCharacter.MAX_VALUE) {
// look at the construction of supplementary characters
// trail forms the ends of it.
return getSurrogateOffset(UTF16.getLeadSurrogate(ch), (char) (ch & SURROGATE_MASK_));
} else {
// return -1 if there is an error, in this case we return
return -1;
}
}
/**
* <p>
* Parses the inputstream and creates the trie index with it.
* </p>
* <p>
* This is overwritten by the child classes.
*
* @param inputStream input stream containing the trie information
* @exception IOException thrown when data reading fails.
*/
protected void unserialize(InputStream inputStream) throws IOException {
// indexLength is a multiple of 1024 >> INDEX_STAGE_2_SHIFT_
m_index_ = new char[m_dataOffset_];
DataInputStream input = new DataInputStream(inputStream);
for (int i = 0; i < m_dataOffset_; i++) {
m_index_[i] = input.readChar();
}
}
/**
* Determines if this is a 16 bit trie
*
* @return true if this is a 16 bit trie
*/
protected final boolean isCharTrie() {
return (m_options_ & HEADER_OPTIONS_DATA_IS_32_BIT_) == 0;
}
// private data members --------------------------------------------
/**
* Latin 1 option mask
*/
protected static final int HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_ = 0x200;
/**
* Constant number to authenticate the byte block
*/
protected static final int HEADER_SIGNATURE_ = 0x54726965;
/**
* Header option formatting
*/
private static final int HEADER_OPTIONS_SHIFT_MASK_ = 0xF;
protected static final int HEADER_OPTIONS_INDEX_SHIFT_ = 4;
protected static final int HEADER_OPTIONS_DATA_IS_32_BIT_ = 0x100;
/**
* 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>
*/
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
*/
private final boolean checkHeader(int signature) {
// check the signature
// Trie in big-endian US-ASCII (0x54726965).
// Magic number to authenticate the data.
if (signature != HEADER_SIGNATURE_) {
return false;
}
if ((m_options_ & HEADER_OPTIONS_SHIFT_MASK_) != INDEX_STAGE_1_SHIFT_
|| ((m_options_ >> HEADER_OPTIONS_INDEX_SHIFT_) & HEADER_OPTIONS_SHIFT_MASK_) != INDEX_STAGE_2_SHIFT_) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,652 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* 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 jdk_internal.bidi.icu.impl;
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
*/
public abstract 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
*/
public abstract 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 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;
}
}

View File

@ -0,0 +1,170 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* 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 jdk_internal.bidi.icu.impl;
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;
}
}

View File

@ -0,0 +1,270 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* 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) 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.
*/
package jdk_internal.bidi.icu.impl;
import java.io.IOException;
import java.nio.ByteBuffer;
import jdk_internal.bidi.icu.lang.UCharacter;
public final class UBiDiProps {
// constructors etc. --------------------------------------------------- ***
// port of ubidi_openProps()
private UBiDiProps() throws IOException {
ByteBuffer bytes = ICUBinary.getRequiredData(DATA_FILE_NAME);
readData(bytes);
}
private void readData(ByteBuffer bytes) throws IOException {
// read the header
ICUBinary.readHeader(bytes, FMT, new IsAcceptable());
// read indexes[]
int i, count;
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] = bytes.getInt();
}
// read the trie
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] = bytes.getInt();
}
}
// read jgArray[]
count = indexes[IX_JG_LIMIT] - indexes[IX_JG_START];
jgArray = new byte[count];
for (i = 0; i < count; ++i) {
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 static final class IsAcceptable implements ICUBinary.Authenticate {
public boolean isDataVersionAcceptable(byte version[]) {
return version[0] == 2;
}
}
// property access functions ------------------------------------------- ***
public final int getClass(int 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 Trie2_16 trie;
// data format constants ----------------------------------------------- ***
@SuppressWarnings("deprecation")
private static final String DATA_FILE_NAME = "/assets/eagler/icudt/ubidi.icu";
/* format "BiDi" */
private static final int FMT = 0x42694469;
/* indexes into indexes[] */
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 RuntimeException("Missing resource: \"" + DATA_FILE_NAME + "\"; Reason: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,627 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* 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) 1996-2014, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
package jdk_internal.bidi.icu.impl;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Iterator;
import jdk_internal.bidi.icu.lang.UCharacter.HangulSyllableType;
import jdk_internal.bidi.icu.lang.UCharacter.NumericType;
import jdk_internal.bidi.icu.text.UTF16;
import jdk_internal.bidi.icu.text.UnicodeSet;
import jdk_internal.bidi.icu.util.VersionInfo;
/**
* <p>
* Internal class used for Unicode character property database.
* </p>
* <p>
* This classes store binary data read from uprops.icu. It does not have the
* capability to parse the data into more high-level information. It only
* returns bytes of information when required.
* </p>
* <p>
* Due to the form most commonly used for retrieval, array of char is used to
* store the binary data.
* </p>
* <p>
* UCharacterPropertyDB also contains information on accessing indexes to
* significant points in the binary data.
* </p>
* <p>
* Responsibility for molding the binary data into more meaning form lies on
* <a href=UCharacter.html>UCharacter</a>.
* </p>
*
* @author Syn Wee Quek
* @since release 2.1, february 1st 2002
*/
public final class UCharacterProperty {
// public data members -----------------------------------------------
/*
* public singleton instance
*/
public static final UCharacterProperty INSTANCE;
/**
* Trie data
*/
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;
/** 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 ----------------------------------------------------
/**
* 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) {
return m_trie_.get(ch);
}
/**
* Gets the unicode additional properties. Java version of C
* u_getUnicodeProperties().
*
* @param codepoint codepoint whose additional properties is to be retrieved
* @param column The column index.
* @return unicode properties
*/
public int getAdditional(int codepoint, int column) {
assert column >= 0;
if (column >= m_additionalColumnsCount_) {
return 0;
}
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 character.
* </p>
* <p>
* This can be useful to avoid emitting code points to receiving processes that
* do not accept newer characters.
* </p>
* <p>
* The data is from the UCD file DerivedAge.txt.
* </p>
* <p>
* This API does not check the validity of the codepoint.
* </p>
*
* @param codepoint The code point.
* @return the Unicode version number
*/
public VersionInfo getAge(int codepoint) {
int version = getAdditional(codepoint, 0) >> AGE_SHIFT_;
return VersionInfo.getInstance((version >> FIRST_NIBBLE_SHIFT_) & LAST_NIBBLE_MASK_,
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
* surrogate characters are done
*
* @param lead lead surrogate character
* @param trail trailing surrogate character
* @return code point of the supplementary character
*/
public static int getRawSupplementary(char lead, char trail) {
return (lead << LEAD_SURROGATE_SHIFT_) + trail + SURROGATE_OFFSET_;
}
/**
* Gets the type mask
*
* @param type character type
* @return mask
*/
public static final int getMask(int type) {
return 1 << type;
}
/**
* 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 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 -----------------------------------------------
/**
* Extra property trie
*/
Trie2_16 m_additionalTrie_;
/**
* Extra property vectors, 1st column for age and second for binary properties.
*/
int m_additionalVectors_[];
/**
* Number of additional columns
*/
int m_additionalColumnsCount_;
/**
* Maximum values for block, bits used as in vector word 0
*/
int m_maxBlockScriptValue_;
/**
* Maximum values for script, bits used as in vector word 0
*/
int m_maxJTGValue_;
/**
* Script_Extensions data
*/
public char[] m_scriptExtensions_;
// private variables -------------------------------------------------
/**
* Default name of the datafile
*/
@SuppressWarnings("deprecation")
private static final String DATA_FILE_NAME_ = "/assets/eagler/icudt/uprops.icu";
/**
* 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 masking.
*/
private static final int SURROGATE_OFFSET_ = UTF16.SUPPLEMENTARY_MIN_VALUE
- (UTF16.SURROGATE_MIN_VALUE << LEAD_SURROGATE_SHIFT_) - UTF16.TRAIL_SURROGATE_MIN_VALUE;
// 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 21..20 & 7..0 = Script_Extensions index 3:
* Script value from Script_Extensions 2: Script=Inherited 1: Script=Common 0:
* Script=bits 21..20 & 7..0 21..20 Bits 9..8 of the UScriptCode, or index to
* Script_Extensions 19..17 East Asian Width 16.. 8 UBlockCode 7.. 0
* UScriptCode, or index to Script_Extensions
*/
/**
* Script_Extensions: mask includes Script
*/
public static final int SCRIPT_X_MASK = 0x00f000ff;
// private static final int SCRIPT_X_SHIFT = 22;
// The UScriptCode or Script_Extensions index is split across two bit fields.
// (Starting with Unicode 13/ICU 66/2019 due to more varied Script_Extensions.)
// Shift the high bits right by 12 to assemble the full value.
public static final int SCRIPT_HIGH_MASK = 0x00300000;
public static final int SCRIPT_HIGH_SHIFT = 12;
public static final int MAX_SCRIPT = 0x3ff;
/**
* 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_LOW_MASK.
*/
public static final int SCRIPT_LOW_MASK = 0x000000ff;
public static final int mergeScriptCodeOrIndex(int scriptX) {
return ((scriptX & SCRIPT_HIGH_MASK) >> SCRIPT_HIGH_SHIFT) | (scriptX & SCRIPT_LOW_MASK);
}
/**
* 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
*/
private static final int FIRST_NIBBLE_SHIFT_ = 0x4;
/**
* Second nibble mask
*/
private static final int LAST_NIBBLE_MASK_ = 0xF;
/**
* Age value shift
*/
private static final int AGE_SHIFT_ = 24;
// private constructors --------------------------------------------------
/**
* Constructor
*
* @exception IOException thrown when data reading fails or data corrupted
*/
private UCharacterProperty() throws IOException {
// jar access
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);
// 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
*/
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 RuntimeException("Missing resource: \"" + DATA_FILE_NAME_ + "\"; Reason: " + e.getMessage());
}
}
// 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;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,266 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* 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) 1996-2011, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package jdk_internal.bidi.icu.impl;
import java.io.IOException;
import java.util.Locale;
import jdk_internal.bidi.icu.lang.UCharacter;
import jdk_internal.bidi.icu.text.UTF16;
public 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) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < s.length();) {
int c = Character.codePointAt(s, i);
i += UTF16.getCharCount(c);
if (c >= ' ' && c <= 0x007F) {
if (c == '\\') {
buf.append("\\\\"); // That is, "\\"
} else {
buf.append((char) c);
}
} else {
boolean four = c <= 0xFFFF;
buf.append(four ? "\\u" : "\\U");
buf.append(hex(c, four ? 4 : 8));
}
}
return buf.toString();
}
/* This map must be in ASCENDING ORDER OF THE ESCAPE CODE */
private static final char[] UNESCAPE_MAP = {
/* " 0x22, 0x22 */
/* ' 0x27, 0x27 */
/* ? 0x3F, 0x3F */
/* \ 0x5C, 0x5C */
/* a */ 0x61, 0x07, /* b */ 0x62, 0x08, /* e */ 0x65, 0x1b, /* f */ 0x66, 0x0c, /* n */ 0x6E, 0x0a,
/* r */ 0x72, 0x0d, /* t */ 0x74, 0x09, /* v */ 0x76, 0x0b };
/**
* Convert an escape to a 32-bit code point value. We attempt to parallel the
* icu4c unescapeAt() function.
*
* @param offset16 an array containing offset to the character <em>after</em>
* the backslash. Upon return offset16[0] will be updated to
* point after the escape sequence.
* @return character value from 0 to 10FFFF, or -1 on error.
*/
public static int unescapeAt(String s, int[] offset16) {
int c;
int result = 0;
int n = 0;
int minDig = 0;
int maxDig = 0;
int bitsPerDigit = 4;
int dig;
int i;
boolean braces = false;
/* Check that offset is in range */
int offset = offset16[0];
int length = s.length();
if (offset < 0 || offset >= length) {
return -1;
}
/* Fetch first UChar after '\\' */
c = Character.codePointAt(s, offset);
offset += UTF16.getCharCount(c);
/* Convert hexadecimal and octal escapes */
switch (c) {
case 'u':
minDig = maxDig = 4;
break;
case 'U':
minDig = maxDig = 8;
break;
case 'x':
minDig = 1;
if (offset < length && UTF16.charAt(s, offset) == 0x7B /* { */) {
++offset;
braces = true;
maxDig = 8;
} else {
maxDig = 2;
}
break;
default:
dig = UCharacter.digit(c, 8);
if (dig >= 0) {
minDig = 1;
maxDig = 3;
n = 1; /* Already have first octal digit */
bitsPerDigit = 3;
result = dig;
}
break;
}
if (minDig != 0) {
while (offset < length && n < maxDig) {
c = UTF16.charAt(s, offset);
dig = UCharacter.digit(c, (bitsPerDigit == 3) ? 8 : 16);
if (dig < 0) {
break;
}
result = (result << bitsPerDigit) | dig;
offset += UTF16.getCharCount(c);
++n;
}
if (n < minDig) {
return -1;
}
if (braces) {
if (c != 0x7D /* } */) {
return -1;
}
++offset;
}
if (result < 0 || result >= 0x110000) {
return -1;
}
// If an escape sequence specifies a lead surrogate, see
// if there is a trail surrogate after it, either as an
// escape or as a literal. If so, join them up into a
// supplementary.
if (offset < length && UTF16.isLeadSurrogate((char) result)) {
int ahead = offset + 1;
c = s.charAt(offset); // [sic] get 16-bit code unit
if (c == '\\' && ahead < length) {
int o[] = new int[] { ahead };
c = unescapeAt(s, o);
ahead = o[0];
}
if (UTF16.isTrailSurrogate((char) c)) {
offset = ahead;
result = UCharacterProperty.getRawSupplementary((char) result, (char) c);
}
}
offset16[0] = offset;
return result;
}
/* Convert C-style escapes in table */
for (i = 0; i < UNESCAPE_MAP.length; i += 2) {
if (c == UNESCAPE_MAP[i]) {
offset16[0] = offset;
return UNESCAPE_MAP[i + 1];
} else if (c < UNESCAPE_MAP[i]) {
break;
}
}
/* Map \cX to control-X: X & 0x1F */
if (c == 'c' && offset < length) {
c = UTF16.charAt(s, offset);
offset16[0] = offset + UTF16.getCharCount(c);
return 0x1F & c;
}
/*
* If no special forms are recognized, then consider the backslash to
* generically escape the next character.
*/
offset16[0] = offset;
return c;
}
/**
* Supplies a zero-padded hex representation of an integer (without 0x)
*/
public static String hex(long i, int places) {
if (i == Long.MIN_VALUE)
return "-8000000000000000";
boolean negative = i < 0;
if (negative) {
i = -i;
}
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[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
/**
* 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 <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 <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;
}
return false;
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
}