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