]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/impl/UCharacterName.java
go
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / impl / UCharacterName.java
1 /**\r
2 *******************************************************************************\r
3 * Copyright (C) 1996-2008, International Business Machines Corporation and    *\r
4 * others. All Rights Reserved.                                                *\r
5 *******************************************************************************\r
6 */\r
7 package com.ibm.icu.impl;\r
8 \r
9 import java.io.InputStream;\r
10 import java.io.BufferedInputStream;\r
11 import java.io.IOException;\r
12 import java.util.MissingResourceException;\r
13 \r
14 import com.ibm.icu.text.UTF16;\r
15 import com.ibm.icu.text.UnicodeSet;\r
16 import com.ibm.icu.lang.UCharacter;\r
17 import com.ibm.icu.lang.UCharacterCategory;\r
18 \r
19 /**\r
20 * Internal class to manage character names.\r
21 * Since data for names are stored\r
22 * in an array of char, by default indexes used in this class is refering to\r
23 * a 2 byte count, unless otherwise stated. Cases where the index is refering\r
24 * to a byte count, the index is halved and depending on whether the index is\r
25 * even or odd, the MSB or LSB of the result char at the halved index is\r
26 * returned. For indexes to an array of int, the index is multiplied by 2,\r
27 * result char at the multiplied index and its following char is returned as an\r
28 * int.\r
29 * <a href=../lang/UCharacter.html>UCharacter</a> acts as a public facade for this class\r
30 * Note : 0 - 0x1F are control characters without names in Unicode 3.0\r
31 * @author Syn Wee Quek\r
32 * @since nov0700\r
33 */\r
34 \r
35 public final class UCharacterName\r
36 {\r
37     // public data members ----------------------------------------------\r
38 \r
39     /**\r
40     * Number of lines per group\r
41     * 1 << GROUP_SHIFT_\r
42     */\r
43     public static final int LINES_PER_GROUP_ = 1 << 5;\r
44     /**\r
45      * Maximum number of groups\r
46      */\r
47     public int m_groupcount_ = 0;\r
48 \r
49     // public methods ---------------------------------------------------\r
50 \r
51     /**\r
52      * Gets the only instance of UCharacterName\r
53      * @return only instance of UCharacterName\r
54      * @exception MissingResourceException thrown when reading of name data fails\r
55      */\r
56     public static UCharacterName getInstance()\r
57     {\r
58         if (INSTANCE_ == null) {\r
59             try {\r
60                 INSTANCE_ = new UCharacterName();\r
61             }catch(IOException e){\r
62                 throw new MissingResourceException("Could not construct UCharacterName. Missing unames.icu","","");\r
63             }\r
64             catch (Exception e) {\r
65                 throw new MissingResourceException(e.getMessage(),"","");\r
66             }\r
67         }\r
68         return INSTANCE_;\r
69     }\r
70 \r
71     /**\r
72     * Retrieve the name of a Unicode code point.\r
73     * Depending on <code>choice</code>, the character name written into the\r
74     * buffer is the "modern" name or the name that was defined in Unicode\r
75     * version 1.0.\r
76     * The name contains only "invariant" characters\r
77     * like A-Z, 0-9, space, and '-'.\r
78     *\r
79     * @param ch the code point for which to get the name.\r
80     * @param choice Selector for which name to get.\r
81     * @return if code point is above 0x1fff, null is returned\r
82     */\r
83     public String getName(int ch, int choice)\r
84     {\r
85         if (ch < UCharacter.MIN_VALUE || ch > UCharacter.MAX_VALUE ||\r
86             choice > UCharacterNameChoice.CHAR_NAME_CHOICE_COUNT) {\r
87             return null;\r
88         }\r
89 \r
90         String result = null;\r
91 \r
92         result = getAlgName(ch, choice);\r
93 \r
94         // getting normal character name\r
95         if (result == null || result.length() == 0) {\r
96             if (choice == UCharacterNameChoice.EXTENDED_CHAR_NAME) {\r
97                 result = getExtendedName(ch);\r
98             } else {\r
99                 result = getGroupName(ch, choice);\r
100             }\r
101         }\r
102 \r
103         return result;\r
104     }\r
105 \r
106     /**\r
107     * Find a character by its name and return its code point value\r
108     * @param choice selector to indicate if argument name is a Unicode 1.0\r
109     *        or the most current version\r
110     * @param name the name to search for\r
111     * @return code point\r
112     */\r
113     public int getCharFromName(int choice, String name)\r
114     {\r
115         // checks for illegal arguments\r
116         if (choice >= UCharacterNameChoice.CHAR_NAME_CHOICE_COUNT ||\r
117             name == null || name.length() == 0) {\r
118             return -1;\r
119         }\r
120 \r
121         // try extended names first\r
122         int result = getExtendedChar(name.toLowerCase(), choice);\r
123         if (result >= -1) {\r
124             return result;\r
125         }\r
126 \r
127         String upperCaseName = name.toUpperCase();\r
128         // try algorithmic names first, if fails then try group names\r
129         // int result = getAlgorithmChar(choice, uppercasename);\r
130 \r
131         if (choice != UCharacterNameChoice.UNICODE_10_CHAR_NAME) {\r
132             int count = 0;\r
133             if (m_algorithm_ != null) {\r
134                 count = m_algorithm_.length;\r
135             }\r
136             for (count --; count >= 0; count --) {\r
137                 result = m_algorithm_[count].getChar(upperCaseName);\r
138                 if (result >= 0) {\r
139                     return result;\r
140                 }\r
141             }\r
142         }\r
143 \r
144         if (choice == UCharacterNameChoice.EXTENDED_CHAR_NAME) {\r
145             result = getGroupChar(upperCaseName,\r
146                                   UCharacterNameChoice.UNICODE_CHAR_NAME);\r
147             if (result == -1) {\r
148                 result = getGroupChar(upperCaseName,\r
149                                   UCharacterNameChoice.UNICODE_10_CHAR_NAME);\r
150             }\r
151         }\r
152         else {\r
153             result = getGroupChar(upperCaseName, choice);\r
154         }\r
155         return result;\r
156     }\r
157 \r
158     // these are all UCharacterNameIterator use methods -------------------\r
159 \r
160     /**\r
161     * Reads a block of compressed lengths of 32 strings and expands them into\r
162     * offsets and lengths for each string. Lengths are stored with a\r
163     * variable-width encoding in consecutive nibbles:\r
164     * If a nibble<0xc, then it is the length itself (0 = empty string).\r
165     * If a nibble>=0xc, then it forms a length value with the following\r
166     * nibble.\r
167     * The offsets and lengths arrays must be at least 33 (one more) long\r
168     * because there is no check here at the end if the last nibble is still\r
169     * used.\r
170     * @param index of group string object in array\r
171     * @param offsets array to store the value of the string offsets\r
172     * @param lengths array to store the value of the string length\r
173     * @return next index of the data string immediately after the lengths\r
174     *         in terms of byte address\r
175     */\r
176     public int getGroupLengths(int index, char offsets[], char lengths[])\r
177     {\r
178         char length = 0xffff;\r
179         byte b = 0,\r
180             n = 0;\r
181         int shift;\r
182         index = index * m_groupsize_; // byte count offsets of group strings\r
183         int stringoffset = UCharacterUtility.toInt(\r
184                                  m_groupinfo_[index + OFFSET_HIGH_OFFSET_],\r
185                                  m_groupinfo_[index + OFFSET_LOW_OFFSET_]);\r
186 \r
187         offsets[0] = 0;\r
188 \r
189         // all 32 lengths must be read to get the offset of the first group\r
190         // string\r
191         for (int i = 0; i < LINES_PER_GROUP_; stringoffset ++) {\r
192             b = m_groupstring_[stringoffset];\r
193             shift = 4;\r
194 \r
195             while (shift >= 0) {\r
196                 // getting nibble\r
197                 n = (byte)((b >> shift) & 0x0F);\r
198                 if (length == 0xffff && n > SINGLE_NIBBLE_MAX_) {\r
199                     length = (char)((n - 12) << 4);\r
200                 }\r
201                 else {\r
202                     if (length != 0xffff) {\r
203                        lengths[i] = (char)((length | n) + 12);\r
204                     }\r
205                     else {\r
206                        lengths[i] = (char)n;\r
207                     }\r
208 \r
209                     if (i < LINES_PER_GROUP_) {\r
210                        offsets[i + 1] = (char)(offsets[i] + lengths[i]);\r
211                     }\r
212 \r
213                     length = 0xffff;\r
214                     i ++;\r
215                 }\r
216 \r
217                 shift -= 4;\r
218             }\r
219         }\r
220         return stringoffset;\r
221     }\r
222 \r
223     /**\r
224     * Gets the name of the argument group index.\r
225     * UnicodeData.txt uses ';' as a field separator, so no field can contain\r
226     * ';' as part of its contents. In unames.icu, it is marked as\r
227     * token[';'] == -1 only if the semicolon is used in the data file - which\r
228     * is iff we have Unicode 1.0 names or ISO comments.\r
229     * So, it will be token[';'] == -1 if we store U1.0 names/ISO comments\r
230     * although we know that it will never be part of a name.\r
231     * Equivalent to ICU4C's expandName.\r
232     * @param index of the group name string in byte count\r
233     * @param length of the group name string\r
234     * @param choice of Unicode 1.0 name or the most current name\r
235     * @return name of the group\r
236     */\r
237     public String getGroupName(int index, int length, int choice)\r
238     {\r
239         if (choice == UCharacterNameChoice.UNICODE_10_CHAR_NAME\r
240             || choice == UCharacterNameChoice.ISO_COMMENT_) {\r
241             if (';' >= m_tokentable_.length || m_tokentable_[';'] == 0xFFFF) {\r
242                 // skip the modern name\r
243                 int oldindex = index;\r
244                 index += UCharacterUtility.skipByteSubString(m_groupstring_,\r
245                                                    index, length, (byte)';');\r
246                 length -= (index - oldindex);\r
247                 if (choice == UCharacterNameChoice.ISO_COMMENT_) {\r
248                     // skips the 1.0 Name to the iso comment part\r
249                     oldindex = index;\r
250                     index += UCharacterUtility.skipByteSubString(m_groupstring_,\r
251                                                     index, length, (byte)';');\r
252                     length -= (index - oldindex);\r
253                 }\r
254             }\r
255             else {\r
256                 // the semicolon byte is a token number, therefore only modern\r
257                 // names are stored in unames.dat and there is no such\r
258                 // requested Unicode 1.0 name here\r
259                 length = 0;\r
260             }\r
261         }\r
262 \r
263         synchronized (m_utilStringBuffer_) {\r
264             m_utilStringBuffer_.delete(0, m_utilStringBuffer_.length());\r
265             byte b;\r
266             char token;\r
267             for (int i = 0; i < length;) {\r
268                 b = m_groupstring_[index + i];\r
269                 i ++;\r
270 \r
271                 if (b >= m_tokentable_.length) {\r
272                     if (b == ';') {\r
273                         break;\r
274                     }\r
275                     m_utilStringBuffer_.append(b); // implicit letter\r
276                 }\r
277                 else {\r
278                     token = m_tokentable_[b & 0x00ff];\r
279                     if (token == 0xFFFE) {\r
280                         // this is a lead byte for a double-byte token\r
281                         token = m_tokentable_[b << 8 |\r
282                                           (m_groupstring_[index + i] & 0x00ff)];\r
283                         i ++;\r
284                     }\r
285                     if (token == 0xFFFF) {\r
286                         if (b == ';') {\r
287                             // skip the semicolon if we are seeking extended\r
288                             // names and there was no 2.0 name but there\r
289                             // is a 1.0 name.\r
290                             if (m_utilStringBuffer_.length() == 0 && choice ==\r
291                                    UCharacterNameChoice.EXTENDED_CHAR_NAME) {\r
292                                 continue;\r
293                             }\r
294                             break;\r
295                         }\r
296                         // explicit letter\r
297                         m_utilStringBuffer_.append((char)(b & 0x00ff));\r
298                     }\r
299                     else { // write token word\r
300                         UCharacterUtility.getNullTermByteSubString(\r
301                                 m_utilStringBuffer_, m_tokenstring_, token);\r
302                     }\r
303                 }\r
304             }\r
305 \r
306             if (m_utilStringBuffer_.length() > 0) {\r
307                 return m_utilStringBuffer_.toString();\r
308             }\r
309         }\r
310         return null;\r
311     }\r
312 \r
313     /**\r
314     * Retrieves the extended name\r
315     */\r
316     public String getExtendedName(int ch)\r
317     {\r
318         String result = getName(ch, UCharacterNameChoice.UNICODE_CHAR_NAME);\r
319         if (result == null) {\r
320             if (getType(ch) == UCharacterCategory.CONTROL) {\r
321                 result = getName(ch,\r
322                                  UCharacterNameChoice.UNICODE_10_CHAR_NAME);\r
323             }\r
324             if (result == null) {\r
325                 result = getExtendedOr10Name(ch);\r
326             }\r
327         }\r
328         return result;\r
329     }\r
330 \r
331     /**\r
332      * Gets the group index for the codepoint, or the group before it.\r
333      * @param codepoint\r
334      * @return group index containing codepoint or the group before it.\r
335      */\r
336     public int getGroup(int codepoint)\r
337     {\r
338         int endGroup = m_groupcount_;\r
339         int msb      = getCodepointMSB(codepoint);\r
340         int result   = 0;\r
341         // binary search for the group of names that contains the one for\r
342         // code\r
343         // find the group that contains codepoint, or the highest before it\r
344         while (result < endGroup - 1) {\r
345             int gindex = (result + endGroup) >> 1;\r
346             if (msb < getGroupMSB(gindex)) {\r
347                 endGroup = gindex;\r
348             }\r
349             else {\r
350                 result = gindex;\r
351             }\r
352         }\r
353         return result;\r
354     }\r
355 \r
356     /**\r
357      * Gets the extended and 1.0 name when the most current unicode names\r
358      * fail\r
359      * @param ch codepoint\r
360      * @return name of codepoint extended or 1.0\r
361      */\r
362     public String getExtendedOr10Name(int ch)\r
363     {\r
364         String result = null;\r
365         if (getType(ch) == UCharacterCategory.CONTROL) {\r
366             result = getName(ch,\r
367                              UCharacterNameChoice.UNICODE_10_CHAR_NAME);\r
368         }\r
369         if (result == null) {\r
370             int type = getType(ch);\r
371             // Return unknown if the table of names above is not up to\r
372             // date.\r
373             if (type >= TYPE_NAMES_.length) {\r
374                 result = UNKNOWN_TYPE_NAME_;\r
375             }\r
376             else {\r
377                 result = TYPE_NAMES_[type];\r
378             }\r
379             synchronized (m_utilStringBuffer_) {\r
380                 m_utilStringBuffer_.delete(0, m_utilStringBuffer_.length());\r
381                 m_utilStringBuffer_.append('<');\r
382                 m_utilStringBuffer_.append(result);\r
383                 m_utilStringBuffer_.append('-');\r
384                 String chStr = Integer.toHexString(ch).toUpperCase();\r
385                 int zeros = 4 - chStr.length();\r
386                 while (zeros > 0) {\r
387                     m_utilStringBuffer_.append('0');\r
388                     zeros --;\r
389                 }\r
390                 m_utilStringBuffer_.append(chStr);\r
391                 m_utilStringBuffer_.append('>');\r
392                 result = m_utilStringBuffer_.toString();\r
393             }\r
394         }\r
395         return result;\r
396     }\r
397 \r
398     /**\r
399      * Gets the MSB from the group index\r
400      * @param gindex group index\r
401      * @return the MSB of the group if gindex is valid, -1 otherwise\r
402      */\r
403     public int getGroupMSB(int gindex)\r
404     {\r
405         if (gindex >= m_groupcount_) {\r
406             return -1;\r
407         }\r
408         return m_groupinfo_[gindex * m_groupsize_];\r
409     }\r
410 \r
411     /**\r
412      * Gets the MSB of the codepoint\r
413      * @param codepoint\r
414      * @return the MSB of the codepoint\r
415      */\r
416     public static int getCodepointMSB(int codepoint)\r
417     {\r
418         return codepoint >> GROUP_SHIFT_;\r
419     }\r
420 \r
421     /**\r
422      * Gets the maximum codepoint + 1 of the group\r
423      * @param msb most significant byte of the group\r
424      * @return limit codepoint of the group\r
425      */\r
426     public static int getGroupLimit(int msb)\r
427     {\r
428         return (msb << GROUP_SHIFT_) + LINES_PER_GROUP_;\r
429     }\r
430 \r
431     /**\r
432      * Gets the minimum codepoint of the group\r
433      * @param msb most significant byte of the group\r
434      * @return minimum codepoint of the group\r
435      */\r
436     public static int getGroupMin(int msb)\r
437     {\r
438         return msb << GROUP_SHIFT_;\r
439     }\r
440 \r
441     /**\r
442      * Gets the offset to a group\r
443      * @param codepoint\r
444      * @return offset to a group\r
445      */\r
446     public static int getGroupOffset(int codepoint)\r
447     {\r
448         return codepoint & GROUP_MASK_;\r
449     }\r
450 \r
451     /**\r
452      * Gets the minimum codepoint of a group\r
453      * @param codepoint\r
454      * @return minimum codepoint in the group which codepoint belongs to\r
455      */\r
456     ///CLOVER:OFF\r
457     public static int getGroupMinFromCodepoint(int codepoint)\r
458     {\r
459         return codepoint & ~GROUP_MASK_;\r
460     }\r
461     ///CLOVER:ON\r
462 \r
463     /**\r
464      * Get the Algorithm range length\r
465      * @return Algorithm range length\r
466      */\r
467     public int getAlgorithmLength()\r
468     {\r
469         return m_algorithm_.length;\r
470     }\r
471 \r
472     /**\r
473      * Gets the start of the range\r
474      * @param index algorithm index\r
475      * @return algorithm range start\r
476      */\r
477     public int getAlgorithmStart(int index)\r
478     {\r
479         return m_algorithm_[index].m_rangestart_;\r
480     }\r
481 \r
482     /**\r
483      * Gets the end of the range\r
484      * @param index algorithm index\r
485      * @return algorithm range end\r
486      */\r
487     public int getAlgorithmEnd(int index)\r
488     {\r
489         return m_algorithm_[index].m_rangeend_;\r
490     }\r
491 \r
492     /**\r
493      * Gets the Algorithmic name of the codepoint\r
494      * @param index algorithmic range index\r
495      * @param codepoint\r
496      * @return algorithmic name of codepoint\r
497      */\r
498     public String getAlgorithmName(int index, int codepoint)\r
499     {\r
500         String result = null;\r
501         synchronized (m_utilStringBuffer_) {\r
502             m_utilStringBuffer_.delete(0, m_utilStringBuffer_.length());\r
503             m_algorithm_[index].appendName(codepoint, m_utilStringBuffer_);\r
504             result = m_utilStringBuffer_.toString();\r
505         }\r
506         return result;\r
507     }\r
508 \r
509     /**\r
510     * Gets the group name of the character\r
511     * @param ch character to get the group name\r
512     * @param choice name choice selector to choose a unicode 1.0 or newer name\r
513     */\r
514     public synchronized String getGroupName(int ch, int choice)\r
515     {\r
516         // gets the msb\r
517         int msb   = getCodepointMSB(ch);\r
518         int group = getGroup(ch);\r
519 \r
520         // return this if it is an exact match\r
521         if (msb == m_groupinfo_[group * m_groupsize_]) {\r
522             int index = getGroupLengths(group, m_groupoffsets_,\r
523                                         m_grouplengths_);\r
524             int offset = ch & GROUP_MASK_;\r
525             return getGroupName(index + m_groupoffsets_[offset],\r
526                                 m_grouplengths_[offset], choice);\r
527         }\r
528 \r
529         return null;\r
530     }\r
531 \r
532     // these are transliterator use methods ---------------------------------\r
533 \r
534     /**\r
535      * Gets the maximum length of any codepoint name.\r
536      * Equivalent to uprv_getMaxCharNameLength.\r
537      * @return the maximum length of any codepoint name\r
538      */\r
539     public int getMaxCharNameLength()\r
540     {\r
541         if (initNameSetsLengths()) {\r
542             return m_maxNameLength_;\r
543         }\r
544         else {\r
545             return 0;\r
546         }\r
547     }\r
548 \r
549     /**\r
550      * Gets the maximum length of any iso comments.\r
551      * Equivalent to uprv_getMaxISOCommentLength.\r
552      * @return the maximum length of any codepoint name\r
553      */\r
554     ///CLOVER:OFF\r
555     public int getMaxISOCommentLength()\r
556     {\r
557         if (initNameSetsLengths()) {\r
558             return m_maxISOCommentLength_;\r
559         }\r
560         else {\r
561             return 0;\r
562         }\r
563     }\r
564     ///CLOVER:ON\r
565 \r
566     /**\r
567      * Fills set with characters that are used in Unicode character names.\r
568      * Equivalent to uprv_getCharNameCharacters.\r
569      * @param set USet to receive characters. Existing contents are deleted.\r
570      */\r
571     public void getCharNameCharacters(UnicodeSet set)\r
572     {\r
573         convert(m_nameSet_, set);\r
574     }\r
575 \r
576     /**\r
577      * Fills set with characters that are used in Unicode character names.\r
578      * Equivalent to uprv_getISOCommentCharacters.\r
579      * @param set USet to receive characters. Existing contents are deleted.\r
580      */\r
581     ///CLOVER:OFF\r
582     public void getISOCommentCharacters(UnicodeSet set)\r
583     {\r
584         convert(m_ISOCommentSet_, set);\r
585     }\r
586     ///CLOVER:ON\r
587 \r
588     // package private inner class --------------------------------------\r
589 \r
590     /**\r
591     * Algorithmic name class\r
592     */\r
593     static final class AlgorithmName\r
594     {\r
595         // package private data members ----------------------------------\r
596 \r
597         /**\r
598         * Constant type value of the different AlgorithmName\r
599         */\r
600         static final int TYPE_0_ = 0;\r
601         static final int TYPE_1_ = 1;\r
602 \r
603         // package private constructors ----------------------------------\r
604 \r
605         /**\r
606         * Constructor\r
607         */\r
608         AlgorithmName()\r
609         {\r
610         }\r
611 \r
612         // package private methods ---------------------------------------\r
613 \r
614         /**\r
615         * Sets the information for accessing the algorithmic names\r
616         * @param rangestart starting code point that lies within this name group\r
617         * @param rangeend end code point that lies within this name group\r
618         * @param type algorithm type. There's 2 kinds of algorithmic type. First\r
619         *        which uses code point as part of its name and the other uses\r
620         *        variant postfix strings\r
621         * @param variant algorithmic variant\r
622         * @return true if values are valid\r
623         */\r
624         boolean setInfo(int rangestart, int rangeend, byte type, byte variant)\r
625         {\r
626             if (rangestart >= UCharacter.MIN_VALUE && rangestart <= rangeend\r
627                 && rangeend <= UCharacter.MAX_VALUE &&\r
628                 (type == TYPE_0_ || type == TYPE_1_)) {\r
629                 m_rangestart_ = rangestart;\r
630                 m_rangeend_ = rangeend;\r
631                 m_type_ = type;\r
632                 m_variant_ = variant;\r
633                 return true;\r
634             }\r
635             return false;\r
636         }\r
637 \r
638         /**\r
639         * Sets the factor data\r
640         * @param factor Array of factor\r
641         * @return true if factors are valid\r
642         */\r
643         boolean setFactor(char factor[])\r
644         {\r
645             if (factor.length == m_variant_) {\r
646                 m_factor_ = factor;\r
647                 return true;\r
648             }\r
649             return false;\r
650         }\r
651 \r
652         /**\r
653         * Sets the name prefix\r
654         * @param prefix\r
655         * @return true if prefix is set\r
656         */\r
657         boolean setPrefix(String prefix)\r
658         {\r
659             if (prefix != null && prefix.length() > 0) {\r
660                 m_prefix_ = prefix;\r
661                 return true;\r
662             }\r
663             return false;\r
664         }\r
665 \r
666         /**\r
667         * Sets the variant factorized name data\r
668         * @param string variant factorized name data\r
669         * @return true if values are set\r
670         */\r
671         boolean setFactorString(byte string[])\r
672         {\r
673             // factor and variant string can be empty for things like\r
674             // hanggul code points\r
675             m_factorstring_ = string;\r
676             return true;\r
677         }\r
678 \r
679         /**\r
680         * Checks if code point lies in Algorithm object at index\r
681         * @param ch code point\r
682         */\r
683         boolean contains(int ch)\r
684         {\r
685             return m_rangestart_ <= ch && ch <= m_rangeend_;\r
686         }\r
687 \r
688         /**\r
689         * Appends algorithm name of code point into StringBuffer.\r
690         * Note this method does not check for validity of code point in Algorithm,\r
691         * result is undefined if code point does not belong in Algorithm.\r
692         * @param ch code point\r
693         * @param str StringBuffer to append to\r
694         */\r
695         void appendName(int ch, StringBuffer str)\r
696         {\r
697             str.append(m_prefix_);\r
698             switch (m_type_)\r
699             {\r
700                 case TYPE_0_:\r
701                     // prefix followed by hex digits indicating variants\r
702                     Utility.hex(ch, m_variant_, str);\r
703                     break;\r
704                 case TYPE_1_:\r
705                     // prefix followed by factorized-elements\r
706                     int offset = ch - m_rangestart_;\r
707                     int indexes[] = m_utilIntBuffer_;\r
708                     int factor;\r
709 \r
710                     // write elements according to the factors\r
711                     // the factorized elements are determined by modulo\r
712                     // arithmetic\r
713                     synchronized (m_utilIntBuffer_) {\r
714                         for (int i = m_variant_ - 1; i > 0; i --)\r
715                         {\r
716                             factor = m_factor_[i] & 0x00FF;\r
717                             indexes[i] = offset % factor;\r
718                             offset /= factor;\r
719                         }\r
720 \r
721                         // we don't need to calculate the last modulus because\r
722                         // start <= code <= end guarantees here that\r
723                         // code <= factors[0]\r
724                         indexes[0] = offset;\r
725 \r
726                         // joining up the factorized strings\r
727                         str.append(getFactorString(indexes, m_variant_));\r
728                     }\r
729                     break;\r
730             }\r
731         }\r
732 \r
733         /**\r
734         * Gets the character for the argument algorithmic name\r
735         * @return the algorithmic char or -1 otherwise.\r
736         */\r
737         int getChar(String name)\r
738         {\r
739             int prefixlen = m_prefix_.length();\r
740             if (name.length() < prefixlen ||\r
741                 !m_prefix_.equals(name.substring(0, prefixlen))) {\r
742                 return -1;\r
743             }\r
744 \r
745             switch (m_type_)\r
746             {\r
747                 case TYPE_0_ :\r
748                 try\r
749                 {\r
750                     int result = Integer.parseInt(name.substring(prefixlen),\r
751                                                   16);\r
752                     // does it fit into the range?\r
753                     if (m_rangestart_ <= result && result <= m_rangeend_) {\r
754                         return result;\r
755                     }\r
756                 }\r
757                 catch (NumberFormatException e)\r
758                 {\r
759                     return -1;\r
760                 }\r
761                 break;\r
762                 case TYPE_1_ :\r
763                     // repetitative suffix name comparison done here\r
764                     // offset is the character code - start\r
765                     for (int ch = m_rangestart_; ch <= m_rangeend_; ch ++)\r
766                     {\r
767                         int offset = ch - m_rangestart_;\r
768                         int indexes[] = m_utilIntBuffer_;\r
769                         int factor;\r
770 \r
771                         // write elements according to the factors\r
772                         // the factorized elements are determined by modulo\r
773                         // arithmetic\r
774                         synchronized (m_utilIntBuffer_) {\r
775                             for (int i = m_variant_ - 1; i > 0; i --)\r
776                             {\r
777                                 factor = m_factor_[i] & 0x00FF;\r
778                                 indexes[i] = offset % factor;\r
779                                 offset /= factor;\r
780                             }\r
781 \r
782                             // we don't need to calculate the last modulus\r
783                             // because start <= code <= end guarantees here that\r
784                             // code <= factors[0]\r
785                             indexes[0] = offset;\r
786 \r
787                             // joining up the factorized strings\r
788                             if (compareFactorString(indexes, m_variant_, name,\r
789                                                     prefixlen)) {\r
790                                 return ch;\r
791                             }\r
792                         }\r
793                     }\r
794             }\r
795 \r
796             return -1;\r
797         }\r
798 \r
799         /**\r
800          * Adds all chars in the set of algorithmic names into the set.\r
801          * Equivalent to part of calcAlgNameSetsLengths.\r
802          * @param set int set to add the chars of the algorithm names into\r
803          * @param maxlength maximum length to compare to\r
804          * @return the length that is either maxlength of the length of this\r
805          *         algorithm name if it is longer than maxlength\r
806          */\r
807         int add(int set[], int maxlength)\r
808         {\r
809             // prefix length\r
810             int length = UCharacterName.add(set, m_prefix_);\r
811             switch (m_type_) {\r
812                 case TYPE_0_ : {\r
813                     // name = prefix + (range->variant times) hex-digits\r
814                     // prefix\r
815                     length += m_variant_;\r
816                     /* synwee to check\r
817                      * addString(set, (const char *)(range + 1))\r
818                                        + range->variant;*/\r
819                     break;\r
820                 }\r
821                 case TYPE_1_ : {\r
822                     // name = prefix factorized-elements\r
823                     // get the set and maximum factor suffix length for each\r
824                     // factor\r
825                     for (int i = m_variant_ - 1; i > 0; i --)\r
826                     {\r
827                         int maxfactorlength = 0;\r
828                         int count = 0;\r
829                         for (int factor = m_factor_[i]; factor > 0; -- factor) {\r
830                             synchronized (m_utilStringBuffer_) {\r
831                                 m_utilStringBuffer_.delete(0,\r
832                                                 m_utilStringBuffer_.length());\r
833                                 count\r
834                                   = UCharacterUtility.getNullTermByteSubString(\r
835                                                 m_utilStringBuffer_,\r
836                                                 m_factorstring_, count);\r
837                                 UCharacterName.add(set, m_utilStringBuffer_);\r
838                                 if (m_utilStringBuffer_.length()\r
839                                                             > maxfactorlength)\r
840                                 {\r
841                                     maxfactorlength\r
842                                                 = m_utilStringBuffer_.length();\r
843                                 }\r
844                             }\r
845                         }\r
846                         length += maxfactorlength;\r
847                     }\r
848                 }\r
849             }\r
850             if (length > maxlength) {\r
851                 return length;\r
852             }\r
853             return maxlength;\r
854         }\r
855 \r
856         // private data members ------------------------------------------\r
857 \r
858         /**\r
859         * Algorithmic data information\r
860         */\r
861         private int m_rangestart_;\r
862         private int m_rangeend_;\r
863         private byte m_type_;\r
864         private byte m_variant_;\r
865         private char m_factor_[];\r
866         private String m_prefix_;\r
867         private byte m_factorstring_[];\r
868         /**\r
869          * Utility StringBuffer\r
870          */\r
871         private StringBuffer m_utilStringBuffer_ = new StringBuffer();\r
872         /**\r
873          * Utility int buffer\r
874          */\r
875         private int m_utilIntBuffer_[] = new int[256];\r
876 \r
877         // private methods -----------------------------------------------\r
878 \r
879         /**\r
880         * Gets the indexth string in each of the argument factor block\r
881         * @param index array with each index corresponding to each factor block\r
882         * @param length length of the array index\r
883         * @return the combined string of the array of indexth factor string in\r
884         *         factor block\r
885         */\r
886         private String getFactorString(int index[], int length)\r
887         {\r
888             int size = m_factor_.length;\r
889             if (index == null || length != size) {\r
890                 return null;\r
891             }\r
892 \r
893             synchronized (m_utilStringBuffer_) {\r
894                 m_utilStringBuffer_.delete(0, m_utilStringBuffer_.length());\r
895                 int count = 0;\r
896                 int factor;\r
897                 size --;\r
898                 for (int i = 0; i <= size; i ++) {\r
899                     factor = m_factor_[i];\r
900                     count = UCharacterUtility.skipNullTermByteSubString(\r
901                                              m_factorstring_, count, index[i]);\r
902                     count = UCharacterUtility.getNullTermByteSubString(\r
903                                           m_utilStringBuffer_, m_factorstring_,\r
904                                           count);\r
905                     if (i != size) {\r
906                         count = UCharacterUtility.skipNullTermByteSubString(\r
907                                                        m_factorstring_, count,\r
908                                                        factor - index[i] - 1);\r
909                     }\r
910                 }\r
911                 return m_utilStringBuffer_.toString();\r
912             }\r
913         }\r
914 \r
915         /**\r
916         * Compares the indexth string in each of the argument factor block with\r
917         * the argument string\r
918         * @param index array with each index corresponding to each factor block\r
919         * @param length index array length\r
920         * @param str string to compare with\r
921         * @param offset of str to start comparison\r
922         * @return true if string matches\r
923         */\r
924         private boolean compareFactorString(int index[], int length, String str,\r
925                                             int offset)\r
926         {\r
927             int size = m_factor_.length;\r
928             if (index == null || length != size)\r
929                 return false;\r
930 \r
931             int count = 0;\r
932             int strcount = offset;\r
933             int factor;\r
934             size --;\r
935             for (int i = 0; i <= size; i ++)\r
936             {\r
937                 factor = m_factor_[i];\r
938                 count = UCharacterUtility.skipNullTermByteSubString(\r
939                                           m_factorstring_, count, index[i]);\r
940                 strcount = UCharacterUtility.compareNullTermByteSubString(str,\r
941                                           m_factorstring_, strcount, count);\r
942                 if (strcount < 0) {\r
943                     return false;\r
944                 }\r
945 \r
946                 if (i != size) {\r
947                     count = UCharacterUtility.skipNullTermByteSubString(\r
948                                   m_factorstring_, count, factor - index[i]);\r
949                 }\r
950             }\r
951             if (strcount != str.length()) {\r
952                 return false;\r
953             }\r
954             return true;\r
955         }\r
956     }\r
957 \r
958     // package private data members --------------------------------------\r
959 \r
960     /**\r
961      * Size of each groups\r
962      */\r
963     int m_groupsize_ = 0;\r
964 \r
965     // package private methods --------------------------------------------\r
966 \r
967     /**\r
968     * Sets the token data\r
969     * @param token array of tokens\r
970     * @param tokenstring array of string values of the tokens\r
971     * @return false if there is a data error\r
972     */\r
973     boolean setToken(char token[], byte tokenstring[])\r
974     {\r
975         if (token != null && tokenstring != null && token.length > 0 &&\r
976             tokenstring.length > 0) {\r
977             m_tokentable_ = token;\r
978             m_tokenstring_ = tokenstring;\r
979             return true;\r
980         }\r
981         return false;\r
982     }\r
983 \r
984     /**\r
985     * Set the algorithm name information array\r
986     * @param alg Algorithm information array\r
987     * @return true if the group string offset has been set correctly\r
988     */\r
989     boolean setAlgorithm(AlgorithmName alg[])\r
990     {\r
991         if (alg != null && alg.length != 0) {\r
992             m_algorithm_ = alg;\r
993             return true;\r
994         }\r
995         return false;\r
996     }\r
997 \r
998     /**\r
999     * Sets the number of group and size of each group in number of char\r
1000     * @param count number of groups\r
1001     * @param size size of group in char\r
1002     * @return true if group size is set correctly\r
1003     */\r
1004     boolean setGroupCountSize(int count, int size)\r
1005     {\r
1006         if (count <= 0 || size <= 0) {\r
1007             return false;\r
1008         }\r
1009         m_groupcount_ = count;\r
1010         m_groupsize_ = size;\r
1011         return true;\r
1012     }\r
1013 \r
1014     /**\r
1015     * Sets the group name data\r
1016     * @param group index information array\r
1017     * @param groupstring name information array\r
1018     * @return false if there is a data error\r
1019     */\r
1020     boolean setGroup(char group[], byte groupstring[])\r
1021     {\r
1022         if (group != null && groupstring != null && group.length > 0 &&\r
1023             groupstring.length > 0) {\r
1024             m_groupinfo_ = group;\r
1025             m_groupstring_ = groupstring;\r
1026             return true;\r
1027         }\r
1028         return false;\r
1029     }\r
1030 \r
1031     // private data members ----------------------------------------------\r
1032 \r
1033     /**\r
1034     * Data used in unames.icu\r
1035     */\r
1036     private char m_tokentable_[];\r
1037     private byte m_tokenstring_[];\r
1038     private char m_groupinfo_[];\r
1039     private byte m_groupstring_[];\r
1040     private AlgorithmName m_algorithm_[];\r
1041 \r
1042     /**\r
1043     * Group use.  Note - access must be synchronized.\r
1044     */\r
1045     private char m_groupoffsets_[] = new char[LINES_PER_GROUP_ + 1];\r
1046     private char m_grouplengths_[] = new char[LINES_PER_GROUP_ + 1];\r
1047 \r
1048     /**\r
1049     * Default name of the name datafile\r
1050     */\r
1051     private static final String NAME_FILE_NAME_ = ICUResourceBundle.ICU_BUNDLE+"/unames.icu";\r
1052     /**\r
1053     * Shift count to retrieve group information\r
1054     */\r
1055     private static final int GROUP_SHIFT_ = 5;\r
1056     /**\r
1057     * Mask to retrieve the offset for a particular character within a group\r
1058     */\r
1059     private static final int GROUP_MASK_ = LINES_PER_GROUP_ - 1;\r
1060     /**\r
1061     * Default buffer size of datafile\r
1062     */\r
1063     private static final int NAME_BUFFER_SIZE_ = 100000;\r
1064 \r
1065     /**\r
1066     * Position of offsethigh in group information array\r
1067     */\r
1068     private static final int OFFSET_HIGH_OFFSET_ = 1;\r
1069 \r
1070     /**\r
1071     * Position of offsetlow in group information array\r
1072     */\r
1073     private static final int OFFSET_LOW_OFFSET_ = 2;\r
1074     /**\r
1075     * Double nibble indicator, any nibble > this number has to be combined\r
1076     * with its following nibble\r
1077     */\r
1078     private static final int SINGLE_NIBBLE_MAX_ = 11;\r
1079 \r
1080     /*\r
1081      * Maximum length of character names (regular & 1.0).\r
1082      */\r
1083     //private static int MAX_NAME_LENGTH_ = 0;\r
1084     /*\r
1085      * Maximum length of ISO comments.\r
1086      */\r
1087     //private static int MAX_ISO_COMMENT_LENGTH_ = 0;\r
1088 \r
1089     /**\r
1090      * Set of chars used in character names (regular & 1.0).\r
1091      * Chars are platform-dependent (can be EBCDIC).\r
1092      */\r
1093     private int m_nameSet_[] = new int[8];\r
1094     /**\r
1095      * Set of chars used in ISO comments. (regular & 1.0).\r
1096      * Chars are platform-dependent (can be EBCDIC).\r
1097      */\r
1098     private int m_ISOCommentSet_[] = new int[8];\r
1099     /**\r
1100      * Utility StringBuffer\r
1101      */\r
1102     private StringBuffer m_utilStringBuffer_ = new StringBuffer();\r
1103     /**\r
1104      * Utility int buffer\r
1105      */\r
1106     private int m_utilIntBuffer_[] = new int[2];\r
1107     /**\r
1108      * Maximum ISO comment length\r
1109      */\r
1110     private int m_maxISOCommentLength_;\r
1111     /**\r
1112      * Maximum name length\r
1113      */\r
1114     private int m_maxNameLength_;\r
1115     /**\r
1116      * Singleton instance\r
1117      */\r
1118     private static UCharacterName INSTANCE_ = null;\r
1119     /**\r
1120      * Type names used for extended names\r
1121      */\r
1122     private static final String TYPE_NAMES_[] = {"unassigned",\r
1123                                                  "uppercase letter",\r
1124                                                  "lowercase letter",\r
1125                                                  "titlecase letter",\r
1126                                                  "modifier letter",\r
1127                                                  "other letter",\r
1128                                                  "non spacing mark",\r
1129                                                  "enclosing mark",\r
1130                                                  "combining spacing mark",\r
1131                                                  "decimal digit number",\r
1132                                                  "letter number",\r
1133                                                  "other number",\r
1134                                                  "space separator",\r
1135                                                  "line separator",\r
1136                                                  "paragraph separator",\r
1137                                                  "control",\r
1138                                                  "format",\r
1139                                                  "private use area",\r
1140                                                  "surrogate",\r
1141                                                  "dash punctuation",\r
1142                                                  "start punctuation",\r
1143                                                  "end punctuation",\r
1144                                                  "connector punctuation",\r
1145                                                  "other punctuation",\r
1146                                                  "math symbol",\r
1147                                                  "currency symbol",\r
1148                                                  "modifier symbol",\r
1149                                                  "other symbol",\r
1150                                                  "initial punctuation",\r
1151                                                  "final punctuation",\r
1152                                                  "noncharacter",\r
1153                                                  "lead surrogate",\r
1154                                                  "trail surrogate"};\r
1155     /**\r
1156      * Unknown type name\r
1157      */\r
1158     private static final String UNKNOWN_TYPE_NAME_ = "unknown";\r
1159     /**\r
1160      * Not a character type\r
1161      */\r
1162     private static final int NON_CHARACTER_\r
1163                                     = UCharacterCategory.CHAR_CATEGORY_COUNT;\r
1164     /**\r
1165     * Lead surrogate type\r
1166     */\r
1167     private static final int LEAD_SURROGATE_\r
1168                                   = UCharacterCategory.CHAR_CATEGORY_COUNT + 1;\r
1169     /**\r
1170     * Trail surrogate type\r
1171     */\r
1172     private static final int TRAIL_SURROGATE_\r
1173                                   = UCharacterCategory.CHAR_CATEGORY_COUNT + 2;\r
1174     /**\r
1175     * Extended category count\r
1176     */\r
1177     static final int EXTENDED_CATEGORY_\r
1178                                   = UCharacterCategory.CHAR_CATEGORY_COUNT + 3;\r
1179 \r
1180     // private constructor ------------------------------------------------\r
1181 \r
1182     /**\r
1183     * <p>Protected constructor for use in UCharacter.</p>\r
1184     * @exception IOException thrown when data reading fails\r
1185     */\r
1186     private UCharacterName() throws IOException\r
1187     {\r
1188         InputStream is = ICUData.getRequiredStream(NAME_FILE_NAME_);\r
1189         BufferedInputStream b = new BufferedInputStream(is, NAME_BUFFER_SIZE_);\r
1190         UCharacterNameReader reader = new UCharacterNameReader(b);\r
1191         reader.read(this);\r
1192         b.close();\r
1193     }\r
1194 \r
1195     // private methods ---------------------------------------------------\r
1196 \r
1197     /**\r
1198     * Gets the algorithmic name for the argument character\r
1199     * @param ch character to determine name for\r
1200     * @param choice name choice\r
1201     * @return the algorithmic name or null if not found\r
1202     */\r
1203     private String getAlgName(int ch, int choice)\r
1204     {\r
1205         // Do not write algorithmic Unicode 1.0 names because Unihan names are\r
1206         // the same as the modern ones, extension A was only introduced with\r
1207         // Unicode 3.0, and the Hangul syllable block was moved and changed\r
1208         // around Unicode 1.1.5.\r
1209         if (choice != UCharacterNameChoice.UNICODE_10_CHAR_NAME) {\r
1210             // index in terms integer index\r
1211             synchronized (m_utilStringBuffer_) {\r
1212                 m_utilStringBuffer_.delete(0, m_utilStringBuffer_.length());\r
1213 \r
1214                 for (int index = m_algorithm_.length - 1; index >= 0; index --)\r
1215                 {\r
1216                    if (m_algorithm_[index].contains(ch)) {\r
1217                       m_algorithm_[index].appendName(ch, m_utilStringBuffer_);\r
1218                       return m_utilStringBuffer_.toString();\r
1219                    }\r
1220                 }\r
1221             }\r
1222         }\r
1223         return null;\r
1224     }\r
1225 \r
1226     /**\r
1227     * Getting the character with the tokenized argument name\r
1228     * @param name of the character\r
1229     * @return character with the tokenized argument name or -1 if character\r
1230     *         is not found\r
1231     */\r
1232     private synchronized int getGroupChar(String name, int choice)\r
1233     {\r
1234         for (int i = 0; i < m_groupcount_; i ++) {\r
1235             // populating the data set of grouptable\r
1236 \r
1237             int startgpstrindex = getGroupLengths(i, m_groupoffsets_,\r
1238                                                   m_grouplengths_);\r
1239 \r
1240             // shift out to function\r
1241             int result = getGroupChar(startgpstrindex, m_grouplengths_, name,\r
1242                                       choice);\r
1243             if (result != -1) {\r
1244                 return (m_groupinfo_[i * m_groupsize_] << GROUP_SHIFT_)\r
1245                          | result;\r
1246             }\r
1247         }\r
1248         return -1;\r
1249     }\r
1250 \r
1251     /**\r
1252     * Compares and retrieve character if name is found within the argument\r
1253     * group\r
1254     * @param index index where the set of names reside in the group block\r
1255     * @param length list of lengths of the strings\r
1256     * @param name character name to search for\r
1257     * @param choice of either 1.0 or the most current unicode name\r
1258     * @return relative character in the group which matches name, otherwise if\r
1259     *         not found, -1 will be returned\r
1260     */\r
1261     private int getGroupChar(int index, char length[], String name,\r
1262                              int choice)\r
1263     {\r
1264         byte b = 0;\r
1265         char token;\r
1266         int len;\r
1267         int namelen = name.length();\r
1268         int nindex;\r
1269         int count;\r
1270 \r
1271         for (int result = 0; result <= LINES_PER_GROUP_; result ++) {\r
1272             nindex = 0;\r
1273             len = length[result];\r
1274 \r
1275             if (choice == UCharacterNameChoice.UNICODE_10_CHAR_NAME) {\r
1276                 int oldindex = index;\r
1277                 index += UCharacterUtility.skipByteSubString(m_groupstring_,\r
1278                                                      index, len, (byte)';');\r
1279                 len -= (index - oldindex);\r
1280             }\r
1281 \r
1282             // number of tokens is > the length of the name\r
1283             // write each letter directly, and write a token word per token\r
1284             for (count = 0; count < len && nindex != -1 && nindex < namelen;\r
1285                 ) {\r
1286                 b = m_groupstring_[index + count];\r
1287                 count ++;\r
1288 \r
1289                 if (b >= m_tokentable_.length) {\r
1290                     if (name.charAt(nindex ++) != (b & 0xFF)) {\r
1291                         nindex = -1;\r
1292                     }\r
1293                 }\r
1294                 else {\r
1295                     token = m_tokentable_[b & 0xFF];\r
1296                     if (token == 0xFFFE) {\r
1297                         // this is a lead byte for a double-byte token\r
1298                         token = m_tokentable_[b << 8 |\r
1299                                    (m_groupstring_[index + count] & 0x00ff)];\r
1300                         count ++;\r
1301                     }\r
1302                     if (token == 0xFFFF) {\r
1303                         if (name.charAt(nindex ++) != (b & 0xFF)) {\r
1304                             nindex = -1;\r
1305                         }\r
1306                     }\r
1307                     else {\r
1308                         // compare token with name\r
1309                         nindex = UCharacterUtility.compareNullTermByteSubString(\r
1310                                         name, m_tokenstring_, nindex, token);\r
1311                     }\r
1312                 }\r
1313             }\r
1314 \r
1315             if (namelen == nindex &&\r
1316                 (count == len || m_groupstring_[index + count] == ';')) {\r
1317                 return result;\r
1318             }\r
1319 \r
1320             index += len;\r
1321         }\r
1322         return -1;\r
1323     }\r
1324 \r
1325     /**\r
1326     * Gets the character extended type\r
1327     * @param ch character to be tested\r
1328     * @return extended type it is associated with\r
1329     */\r
1330     private static int getType(int ch)\r
1331     {\r
1332         if (UCharacterUtility.isNonCharacter(ch)) {\r
1333             // not a character we return a invalid category count\r
1334             return NON_CHARACTER_;\r
1335         }\r
1336         int result = UCharacter.getType(ch);\r
1337         if (result == UCharacterCategory.SURROGATE) {\r
1338             if (ch <= UTF16.LEAD_SURROGATE_MAX_VALUE) {\r
1339                 result = LEAD_SURROGATE_;\r
1340             }\r
1341             else {\r
1342                 result = TRAIL_SURROGATE_;\r
1343             }\r
1344         }\r
1345         return result;\r
1346     }\r
1347 \r
1348     /**\r
1349     * Getting the character with extended name of the form <....>.\r
1350     * @param name of the character to be found\r
1351     * @param choice name choice\r
1352     * @return character associated with the name, -1 if such character is not\r
1353     *                   found and -2 if we should continue with the search.\r
1354     */\r
1355     private static int getExtendedChar(String name, int choice)\r
1356     {\r
1357         if (name.charAt(0) == '<') {\r
1358             if (choice == UCharacterNameChoice.EXTENDED_CHAR_NAME) {\r
1359                 int endIndex = name.length() - 1;\r
1360                 if (name.charAt(endIndex) == '>') {\r
1361                     int startIndex = name.lastIndexOf('-');\r
1362                     if (startIndex >= 0) { // We've got a category.\r
1363                         startIndex ++;\r
1364                         int result = -1;\r
1365                         try {\r
1366                             result = Integer.parseInt(\r
1367                                         name.substring(startIndex, endIndex),\r
1368                                         16);\r
1369                         }\r
1370                         catch (NumberFormatException e) {\r
1371                             return -1;\r
1372                         }\r
1373                         // Now validate the category name. We could use a\r
1374                         // binary search, or a trie, if we really wanted to.\r
1375                         String type = name.substring(1, startIndex - 1);\r
1376                         int length = TYPE_NAMES_.length;\r
1377                         for (int i = 0; i < length; ++ i) {\r
1378                             if (type.compareTo(TYPE_NAMES_[i]) == 0) {\r
1379                                 if (getType(result) == i) {\r
1380                                     return result;\r
1381                                 }\r
1382                                 break;\r
1383                             }\r
1384                         }\r
1385                     }\r
1386                 }\r
1387             }\r
1388             return -1;\r
1389         }\r
1390         return -2;\r
1391     }\r
1392 \r
1393     // sets of name characters, maximum name lengths -----------------------\r
1394 \r
1395     /**\r
1396      * Adds a codepoint into a set of ints.\r
1397      * Equivalent to SET_ADD.\r
1398      * @param set set to add to\r
1399      * @param ch 16 bit char to add\r
1400      */\r
1401     private static void add(int set[], char ch)\r
1402     {\r
1403         set[ch >>> 5] |= 1 << (ch & 0x1f);\r
1404     }\r
1405 \r
1406     /**\r
1407      * Checks if a codepoint is a part of a set of ints.\r
1408      * Equivalent to SET_CONTAINS.\r
1409      * @param set set to check in\r
1410      * @param ch 16 bit char to check\r
1411      * @return true if codepoint is part of the set, false otherwise\r
1412      */\r
1413     private static boolean contains(int set[], char ch)\r
1414     {\r
1415         return (set[ch >>> 5] & (1 << (ch & 0x1f))) != 0;\r
1416     }\r
1417 \r
1418     /**\r
1419      * Adds all characters of the argument str and gets the length\r
1420      * Equivalent to calcStringSetLength.\r
1421      * @param set set to add all chars of str to\r
1422      * @param str string to add\r
1423      */\r
1424     private static int add(int set[], String str)\r
1425     {\r
1426         int result = str.length();\r
1427 \r
1428         for (int i = result - 1; i >= 0; i --) {\r
1429             add(set, str.charAt(i));\r
1430         }\r
1431         return result;\r
1432     }\r
1433 \r
1434     /**\r
1435      * Adds all characters of the argument str and gets the length\r
1436      * Equivalent to calcStringSetLength.\r
1437      * @param set set to add all chars of str to\r
1438      * @param str string to add\r
1439      */\r
1440     private static int add(int set[], StringBuffer str)\r
1441     {\r
1442         int result = str.length();\r
1443 \r
1444         for (int i = result - 1; i >= 0; i --) {\r
1445             add(set, str.charAt(i));\r
1446         }\r
1447         return result;\r
1448     }\r
1449 \r
1450     /**\r
1451      * Adds all algorithmic names into the name set.\r
1452      * Equivalent to part of calcAlgNameSetsLengths.\r
1453      * @param maxlength length to compare to\r
1454      * @return the maximum length of any possible algorithmic name if it is >\r
1455      *         maxlength, otherwise maxlength is returned.\r
1456      */\r
1457     private int addAlgorithmName(int maxlength)\r
1458     {\r
1459         int result = 0;\r
1460         for (int i = m_algorithm_.length - 1; i >= 0; i --) {\r
1461             result = m_algorithm_[i].add(m_nameSet_, maxlength);\r
1462             if (result > maxlength) {\r
1463                 maxlength = result;\r
1464             }\r
1465         }\r
1466         return maxlength;\r
1467     }\r
1468 \r
1469     /**\r
1470      * Adds all extended names into the name set.\r
1471      * Equivalent to part of calcExtNameSetsLengths.\r
1472      * @param maxlength length to compare to\r
1473      * @return the maxlength of any possible extended name.\r
1474      */\r
1475     private int addExtendedName(int maxlength)\r
1476     {\r
1477         for (int i = TYPE_NAMES_.length - 1; i >= 0; i --) {\r
1478             // for each category, count the length of the category name\r
1479             // plus 9 =\r
1480             // 2 for <>\r
1481             // 1 for -\r
1482             // 6 for most hex digits per code point\r
1483             int length = 9 + add(m_nameSet_, TYPE_NAMES_[i]);\r
1484             if (length > maxlength) {\r
1485                 maxlength = length;\r
1486             }\r
1487         }\r
1488         return maxlength;\r
1489     }\r
1490 \r
1491     /**\r
1492      * Adds names of a group to the argument set.\r
1493      * Equivalent to calcNameSetLength.\r
1494      * @param offset of the group name string in byte count\r
1495      * @param length of the group name string\r
1496      * @param tokenlength array to store the length of each token\r
1497      * @param set to add to\r
1498      * @return the length of the name string and the length of the group\r
1499      *         string parsed\r
1500      */\r
1501     private int[] addGroupName(int offset, int length, byte tokenlength[],\r
1502                                int set[])\r
1503     {\r
1504         int resultnlength = 0;\r
1505         int resultplength = 0;\r
1506         while (resultplength < length) {\r
1507             char b = (char)(m_groupstring_[offset + resultplength] & 0xff);\r
1508             resultplength ++;\r
1509             if (b == ';') {\r
1510                 break;\r
1511             }\r
1512 \r
1513             if (b >= m_tokentable_.length) {\r
1514                 add(set, b); // implicit letter\r
1515                 resultnlength ++;\r
1516             }\r
1517             else {\r
1518                 char token = m_tokentable_[b & 0x00ff];\r
1519                 if (token == 0xFFFE) {\r
1520                     // this is a lead byte for a double-byte token\r
1521                     b = (char)(b << 8 | (m_groupstring_[offset + resultplength]\r
1522                                          & 0x00ff));\r
1523                     token = m_tokentable_[b];\r
1524                     resultplength ++;\r
1525                 }\r
1526                 if (token == 0xFFFF) {\r
1527                     add(set, b);\r
1528                     resultnlength ++;\r
1529                 }\r
1530                 else {\r
1531                     // count token word\r
1532                     // use cached token length\r
1533                     byte tlength = tokenlength[b];\r
1534                     if (tlength == 0) {\r
1535                         synchronized (m_utilStringBuffer_) {\r
1536                             m_utilStringBuffer_.delete(0,\r
1537                                                  m_utilStringBuffer_.length());\r
1538                             UCharacterUtility.getNullTermByteSubString(\r
1539                                            m_utilStringBuffer_, m_tokenstring_,\r
1540                                            token);\r
1541                             tlength = (byte)add(set, m_utilStringBuffer_);\r
1542                         }\r
1543                         tokenlength[b] = tlength;\r
1544                     }\r
1545                     resultnlength += tlength;\r
1546                 }\r
1547             }\r
1548         }\r
1549         m_utilIntBuffer_[0] = resultnlength;\r
1550         m_utilIntBuffer_[1] = resultplength;\r
1551         return m_utilIntBuffer_;\r
1552     }\r
1553 \r
1554     /**\r
1555      * Adds names of all group to the argument set.\r
1556      * Sets the data member m_max*Length_.\r
1557      * Method called only once.\r
1558      * Equivalent to calcGroupNameSetsLength.\r
1559      * @param maxlength length to compare to\r
1560      */\r
1561     private void addGroupName(int maxlength)\r
1562     {\r
1563         int maxisolength = 0;\r
1564         char offsets[] = new char[LINES_PER_GROUP_ + 2];\r
1565         char lengths[] = new char[LINES_PER_GROUP_ + 2];\r
1566         byte tokenlengths[] = new byte[m_tokentable_.length];\r
1567 \r
1568         // enumerate all groups\r
1569         // for (int i = m_groupcount_ - 1; i >= 0; i --) {\r
1570         for (int i = 0; i < m_groupcount_ ; i ++) {\r
1571             int offset = getGroupLengths(i, offsets, lengths);\r
1572             // enumerate all lines in each group\r
1573             // for (int linenumber = LINES_PER_GROUP_ - 1; linenumber >= 0;\r
1574             //    linenumber --) {\r
1575             for (int linenumber = 0; linenumber < LINES_PER_GROUP_;\r
1576                 linenumber ++) {\r
1577                 int lineoffset = offset + offsets[linenumber];\r
1578                 int length = lengths[linenumber];\r
1579                 if (length == 0) {\r
1580                     continue;\r
1581                 }\r
1582 \r
1583                 // read regular name\r
1584                 int parsed[] = addGroupName(lineoffset, length, tokenlengths,\r
1585                                             m_nameSet_);\r
1586                 if (parsed[0] > maxlength) {\r
1587                     // 0 for name length\r
1588                     maxlength = parsed[0];\r
1589                 }\r
1590                 lineoffset += parsed[1];\r
1591                 if (parsed[1] >= length) {\r
1592                     // 1 for parsed group string length\r
1593                     continue;\r
1594                 }\r
1595                 length -= parsed[1];\r
1596                 // read Unicode 1.0 name\r
1597                 parsed = addGroupName(lineoffset, length, tokenlengths,\r
1598                                       m_nameSet_);\r
1599                 if (parsed[0] > maxlength) {\r
1600                     // 0 for name length\r
1601                     maxlength = parsed[0];\r
1602                 }\r
1603                 lineoffset += parsed[1];\r
1604                 if (parsed[1] >= length) {\r
1605                     // 1 for parsed group string length\r
1606                     continue;\r
1607                 }\r
1608                 length -= parsed[1];\r
1609                 // read ISO comment\r
1610                 parsed = addGroupName(lineoffset, length, tokenlengths,\r
1611                                       m_ISOCommentSet_);\r
1612                 if (parsed[1] > maxisolength) {\r
1613                     maxisolength = length;\r
1614                 }\r
1615             }\r
1616         }\r
1617 \r
1618         // set gMax... - name length last for threading\r
1619         m_maxISOCommentLength_ = maxisolength;\r
1620         m_maxNameLength_ = maxlength;\r
1621     }\r
1622 \r
1623     /**\r
1624      * Sets up the name sets and the calculation of the maximum lengths.\r
1625      * Equivalent to calcNameSetsLengths.\r
1626      */\r
1627     private boolean initNameSetsLengths()\r
1628     {\r
1629         if (m_maxNameLength_ > 0) {\r
1630             return true;\r
1631         }\r
1632 \r
1633         String extra = "0123456789ABCDEF<>-";\r
1634         // set hex digits, used in various names, and <>-, used in extended\r
1635         // names\r
1636         for (int i = extra.length() - 1; i >= 0; i --) {\r
1637             add(m_nameSet_, extra.charAt(i));\r
1638         }\r
1639 \r
1640         // set sets and lengths from algorithmic names\r
1641         m_maxNameLength_ = addAlgorithmName(0);\r
1642         // set sets and lengths from extended names\r
1643         m_maxNameLength_ = addExtendedName(m_maxNameLength_);\r
1644         // set sets and lengths from group names, set global maximum values\r
1645         addGroupName(m_maxNameLength_);\r
1646         return true;\r
1647     }\r
1648 \r
1649     /**\r
1650      * Converts the char set cset into a Unicode set uset.\r
1651      * Equivalent to charSetToUSet.\r
1652      * @param set Set of 256 bit flags corresponding to a set of chars.\r
1653      * @param uset USet to receive characters. Existing contents are deleted.\r
1654      */\r
1655     private void convert(int set[], UnicodeSet uset)\r
1656     {\r
1657         uset.clear();\r
1658         if (!initNameSetsLengths()) {\r
1659             return;\r
1660         }\r
1661 \r
1662         // build a char string with all chars that are used in character names\r
1663         for (char c = 255; c > 0; c --) {\r
1664             if (contains(set, c)) {\r
1665                 uset.add(c);\r
1666             }\r
1667         }\r
1668     }\r
1669 }\r