|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package java.lang; |
|
|
|
import java.io.DataInputStream; |
|
import java.io.InputStream; |
|
import java.lang.ref.SoftReference; |
|
import java.util.Arrays; |
|
import java.util.Locale; |
|
import java.util.zip.InflaterInputStream; |
|
import java.security.AccessController; |
|
import java.security.PrivilegedAction; |
|
|
|
class CharacterName { |
|
|
|
private static SoftReference<CharacterName> refCharName; |
|
|
|
|
|
private final byte[] strPool; |
|
private final int[] lookup; |
|
private final int[] bkIndices; |
|
|
|
// name -> hash -> hsIndices -> cpEntries -> code point |
|
private final int[] cpEntries; |
|
private final int[] hsIndices; |
|
|
|
private CharacterName() { |
|
try (DataInputStream dis = new DataInputStream(new InflaterInputStream( |
|
AccessController.doPrivileged(new PrivilegedAction<>() { |
|
public InputStream run() { |
|
return getClass().getResourceAsStream("uniName.dat"); |
|
} |
|
})))) { |
|
|
|
int total = dis.readInt(); |
|
int bkNum = dis.readInt(); |
|
int cpNum = dis.readInt(); |
|
int cpEnd = dis.readInt(); |
|
byte ba[] = new byte[cpEnd]; |
|
lookup = new int[bkNum * 256]; |
|
bkIndices = new int[(Character.MAX_CODE_POINT + 1) >> 8]; |
|
strPool = new byte[total - cpEnd]; |
|
cpEntries = new int[cpNum * 3]; |
|
hsIndices = new int[(cpNum / 2) | 1]; |
|
Arrays.fill(bkIndices, -1); |
|
Arrays.fill(hsIndices, -1); |
|
dis.readFully(ba); |
|
dis.readFully(strPool); |
|
|
|
int nameOff = 0; |
|
int cpOff = 0; |
|
int cp = 0; |
|
int bk = -1; |
|
int prevBk = -1; |
|
int idx = 0; |
|
int next = -1; |
|
int hash = 0; |
|
int hsh = 0; |
|
do { |
|
int len = ba[cpOff++] & 0xff; |
|
if (len == 0) { |
|
len = ba[cpOff++] & 0xff; |
|
|
|
cp = ((ba[cpOff++] & 0xff) << 16) | |
|
((ba[cpOff++] & 0xff) << 8) | |
|
((ba[cpOff++] & 0xff)); |
|
} else { |
|
cp++; |
|
} |
|
|
|
int hi = cp >> 8; |
|
if (prevBk != hi) { |
|
bk++; |
|
bkIndices[hi] = bk; |
|
prevBk = hi; |
|
} |
|
lookup[(bk << 8) + (cp & 0xff)] = (nameOff << 8) | len; |
|
|
|
hash = hashN(strPool, nameOff, len); |
|
hsh = (hash & 0x7fffffff) % hsIndices.length; |
|
next = hsIndices[hsh]; |
|
hsIndices[hsh] = idx; |
|
idx = addCp(idx, hash, next, cp); |
|
nameOff += len; |
|
} while (cpOff < cpEnd); |
|
} catch (Exception x) { |
|
throw new InternalError(x.getMessage(), x); |
|
} |
|
} |
|
|
|
private static final int hashN(byte[] a, int off, int len) { |
|
int h = 1; |
|
while (len-- > 0) { |
|
h = 31 * h + a[off++]; |
|
} |
|
return h; |
|
} |
|
|
|
private int addCp(int idx, int hash, int next, int cp) { |
|
cpEntries[idx++] = hash; |
|
cpEntries[idx++] = next; |
|
cpEntries[idx++] = cp; |
|
return idx; |
|
} |
|
|
|
private int getCpHash(int idx) { return cpEntries[idx]; } |
|
private int getCpNext(int idx) { return cpEntries[idx + 1]; } |
|
private int getCp(int idx) { return cpEntries[idx + 2]; } |
|
|
|
public static CharacterName getInstance() { |
|
SoftReference<CharacterName> ref = refCharName; |
|
CharacterName cname = null; |
|
if (ref == null || (cname = ref.get()) == null) { |
|
cname = new CharacterName(); |
|
refCharName = new SoftReference<>(cname); |
|
} |
|
return cname; |
|
} |
|
|
|
public String getName(int cp) { |
|
int off = 0; |
|
int bk = bkIndices[cp >> 8]; |
|
if (bk == -1 || (off = lookup[(bk << 8) + (cp & 0xff)]) == 0) |
|
return null; |
|
@SuppressWarnings("deprecation") |
|
String result = new String(strPool, 0, off >>> 8, off & 0xff); |
|
return result; |
|
} |
|
|
|
public int getCodePoint(String name) { |
|
byte[] bname = name.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1); |
|
int hsh = hashN(bname, 0, bname.length); |
|
int idx = hsIndices[(hsh & 0x7fffffff) % hsIndices.length]; |
|
while (idx != -1) { |
|
if (getCpHash(idx) == hsh) { |
|
int cp = getCp(idx); |
|
int off = -1; |
|
int bk = bkIndices[cp >> 8]; |
|
if (bk != -1 && (off = lookup[(bk << 8) + (cp & 0xff)]) != 0) { |
|
int len = off & 0xff; |
|
off = off >>> 8; |
|
if (bname.length == len) { |
|
int i = 0; |
|
while (i < len && bname[i] == strPool[off++]) { |
|
i++; |
|
} |
|
if (i == len) { |
|
return cp; |
|
} |
|
} |
|
} |
|
} |
|
idx = getCpNext(idx); |
|
} |
|
return -1; |
|
} |
|
} |