1 /* 2 * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import java.io.DataInputStream; 29 import java.io.InputStream; 30 import java.lang.ref.SoftReference; 31 import java.util.Arrays; 32 import java.util.zip.InflaterInputStream; 33 import java.security.AccessController; 34 import java.security.PrivilegedAction; 35 36 import sun.nio.cs.ISO_8859_1; 37 38 class CharacterName { 39 40 private static SoftReference<CharacterName> refCharName; 41 42 // codepoint -> bkIndex -> lookup -> offset/len 43 private final byte[] strPool; 44 private final int[] lookup; // code point -> offset/len in strPool 45 private final int[] bkIndices; // code point -> lookup index 46 47 // name -> hash -> hsIndices -> cpEntries -> code point 48 private final int[] cpEntries; // code points that have name in strPool 49 private final int[] hsIndices; // chain heads, hash indices into "cps" 50 51 private CharacterName() { 52 try (DataInputStream dis = new DataInputStream(new InflaterInputStream( 53 AccessController.doPrivileged(new PrivilegedAction<>() { 54 public InputStream run() { 55 return getClass().getResourceAsStream("uniName.dat"); 56 } 57 })))) { 58 59 int total = dis.readInt(); 60 int bkNum = dis.readInt(); 61 int cpNum = dis.readInt(); 62 int cpEnd = dis.readInt(); 63 byte ba[] = new byte[cpEnd]; 64 lookup = new int[bkNum * 256]; 65 bkIndices = new int[(Character.MAX_CODE_POINT + 1) >> 8]; 66 strPool = new byte[total - cpEnd]; 67 cpEntries = new int[cpNum * 3]; 68 hsIndices = new int[(cpNum / 2) | 1]; 69 Arrays.fill(bkIndices, -1); 70 Arrays.fill(hsIndices, -1); 71 dis.readFully(ba); 72 dis.readFully(strPool); 73 74 int nameOff = 0; 75 int cpOff = 0; 76 int cp = 0; 77 int bk = -1; 78 int prevBk = -1; // prev bkNo; 79 int idx = 0; 80 int next = -1; 81 int hash = 0; 82 int hsh = 0; 83 do { 84 int len = ba[cpOff++] & 0xff; 85 if (len == 0) { 86 len = ba[cpOff++] & 0xff; 87 // always big-endian 88 cp = ((ba[cpOff++] & 0xff) << 16) | 89 ((ba[cpOff++] & 0xff) << 8) | 90 ((ba[cpOff++] & 0xff)); 91 } else { 92 cp++; 93 } 94 // cp -> name 95 int hi = cp >> 8; 96 if (prevBk != hi) { 97 bk++; 98 bkIndices[hi] = bk; 99 prevBk = hi; 100 } 101 lookup[(bk << 8) + (cp & 0xff)] = (nameOff << 8) | len; 102 // name -> cp 103 hash = hashN(strPool, nameOff, len); 104 hsh = (hash & 0x7fffffff) % hsIndices.length; 105 next = hsIndices[hsh]; 106 hsIndices[hsh] = idx; 107 idx = addCp(idx, hash, next, cp); 108 nameOff += len; 109 } while (cpOff < cpEnd); 110 } catch (Exception x) { 111 throw new InternalError(x.getMessage(), x); 112 } 113 } 114 115 private static final int hashN(byte[] a, int off, int len) { 116 int h = 1; 117 while (len-- > 0) { 118 h = 31 * h + a[off++]; 119 } 120 return h; 121 } 122 123 private int addCp(int idx, int hash, int next, int cp) { 124 cpEntries[idx++] = hash; 125 cpEntries[idx++] = next; 126 cpEntries[idx++] = cp; 127 return idx; 128 } 129 130 private int getCpHash(int idx) { return cpEntries[idx]; } 131 private int getCpNext(int idx) { return cpEntries[idx + 1]; } 132 private int getCp(int idx) { return cpEntries[idx + 2]; } 133 134 public static CharacterName getInstance() { 135 SoftReference<CharacterName> ref = refCharName; 136 CharacterName cname = null; 137 if (ref == null || (cname = ref.get()) == null) { 138 cname = new CharacterName(); 139 refCharName = new SoftReference<>(cname); 140 } 141 return cname; 142 } 143 144 public String getName(int cp) { 145 int off = 0; 146 int bk = bkIndices[cp >> 8]; 147 if (bk == -1 || (off = lookup[(bk << 8) + (cp & 0xff)]) == 0) 148 return null; 149 @SuppressWarnings("deprecation") 150 String result = new String(strPool, 0, off >>> 8, off & 0xff); // ASCII 151 return result; 152 } 153 154 public int getCodePoint(String name) { 155 byte[] bname = name.getBytes(ISO_8859_1.INSTANCE); 156 int hsh = hashN(bname, 0, bname.length); 157 int idx = hsIndices[(hsh & 0x7fffffff) % hsIndices.length]; 158 while (idx != -1) { 159 if (getCpHash(idx) == hsh) { 160 int cp = getCp(idx); 161 int off = -1; 162 int bk = bkIndices[cp >> 8]; 163 if (bk != -1 && (off = lookup[(bk << 8) + (cp & 0xff)]) != 0) { 164 int len = off & 0xff; 165 off = off >>> 8; 166 if (bname.length == len) { 167 int i = 0; 168 while (i < len && bname[i] == strPool[off++]) { 169 i++; 170 } 171 if (i == len) { 172 return cp; 173 } 174 } 175 } 176 } 177 idx = getCpNext(idx); 178 } 179 return -1; 180 } 181 }