• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html#License
3 /*
4  *******************************************************************************
5  * Copyright (C) 2006-2015, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  *******************************************************************************
8  *
9  *******************************************************************************
10  */
11 
12 package com.ibm.icu.charset;
13 
14 import java.io.IOException;
15 import java.nio.ByteBuffer;
16 
17 import com.ibm.icu.impl.ICUBinary;
18 
19 final class UConverterAlias {
20     static final int UNNORMALIZED = 0;
21 
22     static final int STD_NORMALIZED = 1;
23 
24     static final int AMBIGUOUS_ALIAS_MAP_BIT = 0x8000;
25 
26     static final int CONTAINS_OPTION_BIT = 0x4000;
27 
28     static final int CONVERTER_INDEX_MASK = 0xFFF;
29 
30     static final int NUM_RESERVED_TAGS = 2;
31 
32     static final int NUM_HIDDEN_TAGS = 1;
33 
34     static char[] gConverterList = null;
35 
36     static char[] gTagList = null;
37 
38     static char[] gAliasList = null;
39 
40     static char[] gUntaggedConvArray = null;
41 
42     static char[] gTaggedAliasArray = null;
43 
44     static char[] gTaggedAliasLists = null;
45 
46     static char[] gOptionTable = null;
47 
48     static byte[] gStringTable = null;
49 
50     static byte[] gNormalizedStringTable = null;
51 
GET_STRING(int idx)52     private static final String GET_STRING(int idx) {
53         return extractString(gStringTable, 2 * idx);
54     }
55 
GET_NORMALIZED_STRING(int idx)56     private static final String GET_NORMALIZED_STRING(int idx) {
57         return extractString(gNormalizedStringTable, 2 * idx);
58     }
59 
extractString(byte[] sArray, int sBegin)60     private static final String extractString(byte[] sArray, int sBegin) {
61         char[] buf = new char[strlen(sArray, sBegin)];
62         for (int i = 0; i < buf.length; i++) {
63            buf[i] = (char)(sArray[sBegin + i] & 0xff);
64         }
65         return new String(buf);
66     }
67 
strlen(byte[] sArray, int sBegin)68     private static final int strlen(byte[] sArray, int sBegin)
69     {
70         int i = sBegin;
71         while(i < sArray.length && sArray[i++] != 0) {}
72         return i - sBegin - 1;
73     }
74 
75     /*private*/ static final int tocLengthIndex = 0;
76 
77     private static final int converterListIndex = 1;
78 
79     private static final int tagListIndex = 2;
80 
81     private static final int aliasListIndex = 3;
82 
83     private static final int untaggedConvArrayIndex = 4;
84 
85     private static final int taggedAliasArrayIndex = 5;
86 
87     private static final int taggedAliasListsIndex = 6;
88 
89     private static final int optionTableIndex = 7;
90 
91     private static final int stringTableIndex = 8;
92 
93     private static final int normalizedStringTableIndex = 9;
94 
95     private static final int minTocLength = 9; /*
96                                                  * min. tocLength in the file,
97                                                  * does not count the
98                                                  * tocLengthIndex!
99                                                  */
100 
101     private static final int offsetsCount = minTocLength + 1; /*
102                                                                  * length of the
103                                                                  * swapper's
104                                                                  * temporary
105                                                                  * offsets[]
106                                                                  */
107 
108     static ByteBuffer gAliasData = null;
109 
isAlias(String alias)110     private static final boolean isAlias(String alias) {
111         if (alias == null) {
112             throw new IllegalArgumentException("Alias param is null!");
113         }
114         return (alias.length() != 0);
115     }
116 
117     private static final String CNVALIAS_DATA_FILE_NAME = "cnvalias.icu";
118 
haveAliasData()119     private static final synchronized boolean haveAliasData()
120                                                throws IOException{
121         boolean needInit;
122 
123         needInit = gAliasData == null;
124 
125         /* load converter alias data from file if necessary */
126         if (needInit) {
127             ByteBuffer data = null;
128             int[] tableArray = null;
129             int tableStart;
130 
131             ByteBuffer b = ICUBinary.getRequiredData(CNVALIAS_DATA_FILE_NAME);
132             UConverterAliasDataReader reader = new UConverterAliasDataReader(b);
133             tableArray = reader.readToc(offsetsCount);
134 
135             tableStart = tableArray[0];
136             if (tableStart < minTocLength) {
137                 throw new IOException("Invalid data format.");
138             }
139             gConverterList = ICUBinary.getChars(b, tableArray[converterListIndex], 0);
140             gTagList = ICUBinary.getChars(b, tableArray[tagListIndex], 0);
141             gAliasList = ICUBinary.getChars(b, tableArray[aliasListIndex], 0);
142             gUntaggedConvArray = ICUBinary.getChars(b, tableArray[untaggedConvArrayIndex], 0);
143             gTaggedAliasArray = ICUBinary.getChars(b, tableArray[taggedAliasArrayIndex], 0);
144             gTaggedAliasLists = ICUBinary.getChars(b, tableArray[taggedAliasListsIndex], 0);
145             gOptionTable = ICUBinary.getChars(b, tableArray[optionTableIndex], 0);
146             gStringTable = new byte[tableArray[stringTableIndex]*2];
147             b.get(gStringTable);
148             gNormalizedStringTable = new byte[tableArray[normalizedStringTableIndex]*2];
149             b.get(gNormalizedStringTable);
150 
151             data =  ByteBuffer.allocate(0); // dummy UDataMemory object in absence
152                                         // of memory mapping
153 
154             if (gOptionTable[0] != STD_NORMALIZED) {
155                 throw new IOException("Unsupported alias normalization");
156             }
157 
158             if (gAliasData == null) {
159                 gAliasData = data;
160                 data = null;
161             }
162         }
163 
164         return true;
165     }
166 
167     // U_CFUNC const char * io_getConverterName(const char *alias, UErrorCode
168     // *pErrorCode)
169 //    public static final String io_getConverterName(String alias)
170 //                                    throws IOException{
171 //        if (haveAliasData() && isAlias(alias)) {
172 //            boolean[] isAmbigous = new boolean[1];
173 //            int convNum = findConverter(alias, isAmbigous);
174 //            if (convNum < gConverterList.length) {
175 //                return GET_STRING(gConverterList[(int) convNum]);
176 //            }
177 //            /* else converter not found */
178 //        }
179 //        return null;
180 //    }
181 
182     /*
183      * search for an alias return the converter number index for gConverterList
184      */
185     // static U_INLINE uint32_t findConverter(const char *alias, UErrorCode
186     // *pErrorCode)
findConverter(String alias, boolean[] isAmbigous)187     private static final int findConverter(String alias, boolean[] isAmbigous) {
188         int mid, start, limit;
189         int lastMid;
190         int result;
191         StringBuilder strippedName = new StringBuilder();
192         String aliasToCompare;
193 
194         stripForCompare(strippedName, alias);
195         alias = strippedName.toString();
196 
197         /* do a binary search for the alias */
198         start = 0;
199         limit = gUntaggedConvArray.length;
200         mid = limit;
201         lastMid = Integer.MAX_VALUE;
202 
203         for (;;) {
204             mid = (start + limit) / 2;
205             if (lastMid == mid) { /* Have we moved? */
206                 break; /* We haven't moved, and it wasn't found. */
207             }
208             lastMid = mid;
209             aliasToCompare = GET_NORMALIZED_STRING(gAliasList[mid]);
210             result = alias.compareTo(aliasToCompare);
211 
212             if (result < 0) {
213                 limit = mid;
214             } else if (result > 0) {
215                 start = mid;
216             } else {
217                 /*
218                  * Since the gencnval tool folds duplicates into one entry, this
219                  * alias in gAliasList is unique, but different standards may
220                  * map an alias to different converters.
221                  */
222                 if ((gUntaggedConvArray[mid] & AMBIGUOUS_ALIAS_MAP_BIT) != 0) {
223                     isAmbigous[0]=true;
224                 }
225                 /* State whether the canonical converter name contains an option.
226                 This information is contained in this list in order to maintain backward & forward compatibility. */
227                 /*if (containsOption) {
228                     UBool containsCnvOptionInfo = (UBool)gMainTable.optionTable->containsCnvOptionInfo;
229                     *containsOption = (UBool)((containsCnvOptionInfo
230                         && ((gMainTable.untaggedConvArray[mid] & UCNV_CONTAINS_OPTION_BIT) != 0))
231                         || !containsCnvOptionInfo);
232                 }*/
233                 return gUntaggedConvArray[mid] & CONVERTER_INDEX_MASK;
234             }
235         }
236         return Integer.MAX_VALUE;
237     }
238 
239     /**
240      * stripForCompare Remove the underscores, dashes and spaces from
241      * the name, and convert the name to lower case.
242      *
243      * @param dst The destination buffer, which is <= the buffer of name.
244      * @param name The alias to strip
245      * @return the destination buffer.
246      */
stripForCompare(StringBuilder dst, String name)247     public static final StringBuilder stripForCompare(StringBuilder dst, String name) {
248         return io_stripASCIIForCompare(dst, name);
249     }
250 
251     // enum {
252     private static final byte IGNORE = 0;
253     private static final byte ZERO = 1;
254     private static final byte NONZERO = 2;
255     static final byte MINLETTER = 3; /* any values from here on are lowercase letter mappings */
256     // }
257 
258     /* character types for ASCII 00..7F */
259     static final byte asciiTypes[] = new byte[] {
260         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
261         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
262         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
263         ZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, 0, 0, 0, 0, 0, 0,
264         0, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
265         0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0, 0, 0, 0, 0,
266         0, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
267         0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0, 0, 0, 0, 0
268     };
269 
GET_CHAR_TYPE(char c)270     private static final char GET_CHAR_TYPE(char c) {
271         return (char)((c < asciiTypes.length) ? asciiTypes[c] : (char)IGNORE);
272     }
273 
274     /** @see UConverterAlias#compareNames */
io_stripASCIIForCompare(StringBuilder dst, String name)275     private static final StringBuilder io_stripASCIIForCompare(StringBuilder dst, String name) {
276         int nameIndex = 0;
277         char type, nextType;
278         char c1;
279         boolean afterDigit = false;
280 
281         while (nameIndex < name.length()) {
282             c1 = name.charAt(nameIndex++);
283             type = GET_CHAR_TYPE(c1);
284             switch (type) {
285             case IGNORE:
286                 afterDigit = false;
287                 continue; /* ignore all but letters and digits */
288             case ZERO:
289                 if (!afterDigit && nameIndex < name.length()) {
290                     nextType = GET_CHAR_TYPE(name.charAt(nameIndex));
291                     if (nextType == ZERO || nextType == NONZERO) {
292                         continue; /* ignore leading zero before another digit */
293                     }
294                 }
295                 break;
296             case NONZERO:
297                 afterDigit = true;
298                 break;
299             default:
300                 c1 = type; /* lowercased letter */
301                 afterDigit = false;
302                 break;
303             }
304             dst.append(c1);
305         }
306         return dst;
307     }
308 
309     /**
310      * Do a fuzzy compare of a two converter/alias names. The comparison is
311      * case-insensitive. It also ignores the characters '-', '_', and ' ' (dash,
312      * underscore, and space). Thus the strings "UTF-8", "utf_8", and "Utf 8"
313      * are exactly equivalent.
314      *
315      * This is a symmetrical (commutative) operation; order of arguments is
316      * insignificant. This is an important property for sorting the list (when
317      * the list is preprocessed into binary form) and for performing binary
318      * searches on it at run time.
319      *
320      * @param name1
321      *            a converter name or alias, zero-terminated
322      * @param name2
323      *            a converter name or alias, zero-terminated
324      * @return 0 if the names match, or a negative value if the name1 lexically
325      *         precedes name2, or a positive value if the name1 lexically
326      *         follows name2.
327      *
328      * @see UConverterAlias#stripForCompare
329      */
compareNames(String name1, String name2)330     static int compareNames(String name1, String name2){
331         int rc, name1Index = 0, name2Index = 0;
332         char type, nextType;
333         char c1 = 0, c2 = 0;
334         boolean afterDigit1 = false, afterDigit2 = false;
335 
336         for (;;) {
337             while (name1Index < name1.length()) {
338                 c1 = name1.charAt(name1Index++);
339                 type = GET_CHAR_TYPE(c1);
340                 switch (type) {
341                 case IGNORE:
342                     afterDigit1 = false;
343                     continue; /* ignore all but letters and digits */
344                 case ZERO:
345                     if (!afterDigit1 && name1Index < name1.length()) {
346                         nextType = GET_CHAR_TYPE(name1.charAt(name1Index));
347                         if (nextType == ZERO || nextType == NONZERO) {
348                             continue; /* ignore leading zero before another digit */
349                         }
350                     }
351                     break;
352                 case NONZERO:
353                     afterDigit1 = true;
354                     break;
355                 default:
356                     c1 = type; /* lowercased letter */
357                     afterDigit1 = false;
358                     break;
359                 }
360                 break; /* deliver c1 */
361             }
362             while (name2Index < name2.length()) {
363                 c2 = name2.charAt(name2Index++);
364                 type = GET_CHAR_TYPE(c2);
365                 switch (type) {
366                 case IGNORE:
367                     afterDigit2 = false;
368                     continue; /* ignore all but letters and digits */
369                 case ZERO:
370                     if (!afterDigit2 && name1Index < name1.length()) {
371                         nextType = GET_CHAR_TYPE(name2.charAt(name2Index));
372                         if (nextType == ZERO || nextType == NONZERO) {
373                             continue; /* ignore leading zero before another digit */
374                         }
375                     }
376                     break;
377                 case NONZERO:
378                     afterDigit2 = true;
379                     break;
380                 default:
381                     c2 = type; /* lowercased letter */
382                     afterDigit2 = false;
383                     break;
384                 }
385                 break; /* deliver c2 */
386             }
387 
388             /* If we reach the ends of both strings then they match */
389             if (name1Index >= name1.length() && name2Index >= name2.length()) {
390                 return 0;
391             }
392 
393             /* Case-insensitive comparison */
394             rc = (int)c1 - (int)c2;
395             if (rc != 0) {
396                 return rc;
397             }
398         }
399     }
400 
io_countAliases(String alias)401     static int io_countAliases(String alias)
402                         throws IOException{
403         if (haveAliasData() && isAlias(alias)) {
404             boolean[] isAmbigous = new boolean[1];
405             int convNum = findConverter(alias, isAmbigous);
406             if (convNum < gConverterList.length) {
407                 /* tagListNum - 1 is the ALL tag */
408                 int listOffset = gTaggedAliasArray[(gTagList.length - 1)
409                         * gConverterList.length + convNum];
410 
411                 if (listOffset != 0) {
412                     return gTaggedAliasLists[listOffset];
413                 }
414                 /* else this shouldn't happen. internal program error */
415             }
416             /* else converter not found */
417         }
418         return 0;
419     }
420 
421     /**
422      * Return the number of all aliases (and converter names).
423      *
424      * @return the number of all aliases
425      */
426     // U_CFUNC uint16_t io_countTotalAliases(UErrorCode *pErrorCode);
427 //    static int io_countTotalAliases() throws IOException{
428 //        if (haveAliasData()) {
429 //            return (int) gAliasList.length;
430 //        }
431 //        return 0;
432 //    }
433 
434     // U_CFUNC const char * io_getAlias(const char *alias, uint16_t n,
435     // UErrorCode *pErrorCode)
io_getAlias(String alias, int n)436     static String io_getAlias(String alias, int n) throws IOException{
437         if (haveAliasData() && isAlias(alias)) {
438             boolean[] isAmbigous = new boolean[1];
439             int convNum = findConverter(alias,isAmbigous);
440             if (convNum < gConverterList.length) {
441                 /* tagListNum - 1 is the ALL tag */
442                 int listOffset = gTaggedAliasArray[(gTagList.length - 1)
443                         * gConverterList.length + convNum];
444 
445                 if (listOffset != 0) {
446                     //int listCount = gTaggedAliasListsArray[listOffset];
447                     /* +1 to skip listCount */
448                     int currListArrayIndex = listOffset + 1;
449 
450                     return GET_STRING(gTaggedAliasLists[currListArrayIndex + n]);
451                 }
452                 /* else this shouldn't happen. internal program error */
453             }
454             /* else converter not found */
455         }
456         return null;
457     }
458 
459     // U_CFUNC uint16_t io_countStandards(UErrorCode *pErrorCode) {
460 //    static int io_countStandards() throws IOException{
461 //        if (haveAliasData()) {
462 //            return (int) (gTagList.length - NUM_HIDDEN_TAGS);
463 //        }
464 //        return 0;
465 //    }
466 
467     // U_CAPI const char * U_EXPORT2getStandard(uint16_t n, UErrorCode
468     // *pErrorCode)
469 //    static String getStandard(int n) throws IOException{
470 //        if (haveAliasData()) {
471 //            return GET_STRING(gTagList[n]);
472 //        }
473 //        return null;
474 //    }
475 
476     // U_CAPI const char * U_EXPORT2 getStandardName(const char *alias, const
477     // char *standard, UErrorCode *pErrorCode)
getStandardName(String alias, String standard)478     static final String getStandardName(String alias, String standard)throws IOException {
479         if (haveAliasData() && isAlias(alias)) {
480             int listOffset = findTaggedAliasListsOffset(alias, standard);
481 
482             if (0 < listOffset && listOffset < gTaggedAliasLists.length) {
483                 int currListArrayIndex = listOffset + 1;
484                 if (gTaggedAliasLists[0] != 0) {
485                     return GET_STRING(gTaggedAliasLists[currListArrayIndex]);
486                 }
487             }
488         }
489         return null;
490     }
491 
492     // U_CAPI uint16_t U_EXPORT2 countAliases(const char *alias, UErrorCode
493     // *pErrorCode)
countAliases(String alias)494     static int countAliases(String alias) throws IOException{
495         return io_countAliases(alias);
496     }
497 
498     // U_CAPI const char* U_EXPORT2 getAlias(const char *alias, uint16_t n,
499     // UErrorCode *pErrorCode)
getAlias(String alias, int n)500     static String getAlias(String alias, int n) throws IOException{
501         return io_getAlias(alias, n);
502     }
503 
504     // U_CFUNC uint16_t countStandards(void)
505 //    static int countStandards()throws IOException{
506 //        return io_countStandards();
507 //    }
508 
509     /*returns a single Name from the list, will return NULL if out of bounds
510      */
getAvailableName(int n)511     static String getAvailableName (int n){
512         try{
513           if (0 <= n && n <= 0xffff) {
514             String name = bld_getAvailableConverter(n);
515             return name;
516           }
517         }catch(IOException ex){
518             //throw away exception
519         }
520         return null;
521     }
522     // U_CAPI const char * U_EXPORT2 getCanonicalName(const char *alias, const
523     // char *standard, UErrorCode *pErrorCode) {
getCanonicalName(String alias, String standard)524     static String getCanonicalName(String alias, String standard) throws IOException{
525         if (haveAliasData() && isAlias(alias)) {
526             int convNum = findTaggedConverterNum(alias, standard);
527 
528             if (convNum < gConverterList.length) {
529                 return GET_STRING(gConverterList[convNum]);
530             }
531         }
532 
533         return null;
534     }
countAvailable()535     static int countAvailable (){
536         try{
537             return bld_countAvailableConverters();
538         }catch(IOException ex){
539             //throw away exception
540         }
541         return -1;
542     }
543 
544     // U_CAPI UEnumeration * U_EXPORT2 openStandardNames(const char *convName,
545     // const char *standard, UErrorCode *pErrorCode)
546 /*    static final UConverterAliasesEnumeration openStandardNames(String convName, String standard)throws IOException {
547         UConverterAliasesEnumeration aliasEnum = null;
548         if (haveAliasData() && isAlias(convName)) {
549             int listOffset = findTaggedAliasListsOffset(convName, standard);
550 
551 
552              * When listOffset == 0, we want to acknowledge that the converter
553              * name and standard are okay, but there is nothing to enumerate.
554 
555             if (listOffset < gTaggedAliasLists.length) {
556 
557                 UConverterAliasesEnumeration.UAliasContext context = new UConverterAliasesEnumeration.UAliasContext(listOffset, 0);
558                 aliasEnum = new UConverterAliasesEnumeration();
559                 aliasEnum.setContext(context);
560             }
561              else converter or tag not found
562         }
563         return aliasEnum;
564     }*/
565 
566     // static uint32_t getTagNumber(const char *tagname)
getTagNumber(String tagName)567     private static int getTagNumber(String tagName) {
568         if (gTagList != null) {
569             int tagNum;
570             for (tagNum = 0; tagNum < gTagList.length; tagNum++) {
571                 if (tagName.equals(GET_STRING(gTagList[tagNum]))) {
572                     return tagNum;
573                 }
574             }
575         }
576 
577         return Integer.MAX_VALUE;
578     }
579 
580     // static uint32_t findTaggedAliasListsOffset(const char *alias, const char
581     // *standard, UErrorCode *pErrorCode)
findTaggedAliasListsOffset(String alias, String standard)582     private static int findTaggedAliasListsOffset(String alias, String standard) {
583         int idx;
584         int listOffset;
585         int convNum;
586         int tagNum = getTagNumber(standard);
587         boolean[] isAmbigous = new boolean[1];
588         /* Make a quick guess. Hopefully they used a TR22 canonical alias. */
589         convNum = findConverter(alias, isAmbigous);
590 
591         if (tagNum < (gTagList.length - NUM_HIDDEN_TAGS)
592                 && convNum < gConverterList.length) {
593             listOffset = gTaggedAliasArray[tagNum
594                     * gConverterList.length + convNum];
595             if (listOffset != 0
596                     && gTaggedAliasLists[listOffset + 1] != 0) {
597                 return listOffset;
598             }
599             if (isAmbigous[0]==true) {
600                 /*
601                  * Uh Oh! They used an ambiguous alias. We have to search the
602                  * whole swiss cheese starting at the highest standard affinity.
603                  * This may take a while.
604                  */
605 
606                 for (idx = 0; idx < gTaggedAliasArray.length; idx++) {
607                     listOffset = gTaggedAliasArray[idx];
608                     if (listOffset != 0 && isAliasInList(alias, listOffset)) {
609                         int currTagNum = idx / gConverterList.length;
610                         int currConvNum = (idx - currTagNum
611                                 * gConverterList.length);
612                         int tempListOffset = gTaggedAliasArray[tagNum
613                                 * gConverterList.length + currConvNum];
614                         if (tempListOffset != 0
615                                 && gTaggedAliasLists[tempListOffset + 1] != 0) {
616                             return tempListOffset;
617                         }
618                         /*
619                          * else keep on looking We could speed this up by
620                          * starting on the next row because an alias is unique
621                          * per row, right now. This would change if alias
622                          * versioning appears.
623                          */
624                     }
625                 }
626                 /* The standard doesn't know about the alias */
627             }
628             /* else no default name */
629             return 0;
630         }
631         /* else converter or tag not found */
632 
633         return Integer.MAX_VALUE;
634     }
635 
636     /* Return the canonical name */
637     // static uint32_t findTaggedConverterNum(const char *alias, const char
638     // *standard, UErrorCode *pErrorCode)
findTaggedConverterNum(String alias, String standard)639     private static int findTaggedConverterNum(String alias, String standard) {
640         int idx;
641         int listOffset;
642         int convNum;
643         int tagNum = getTagNumber(standard);
644         boolean[] isAmbigous = new boolean[1];
645 
646         /* Make a quick guess. Hopefully they used a TR22 canonical alias. */
647         convNum = findConverter(alias, isAmbigous);
648 
649         if (tagNum < (gTagList.length - NUM_HIDDEN_TAGS)
650                 && convNum < gConverterList.length) {
651             listOffset = gTaggedAliasArray[tagNum
652                     * gConverterList.length + convNum];
653             if (listOffset != 0 && isAliasInList(alias, listOffset)) {
654                 return convNum;
655             }
656             if (isAmbigous[0] == true) {
657                 /*
658                  * Uh Oh! They used an ambiguous alias. We have to search one
659                  * slice of the swiss cheese. We search only in the requested
660                  * tag, not the whole thing. This may take a while.
661                  */
662                 int convStart = (tagNum) * gConverterList.length;
663                 int convLimit = (tagNum + 1) * gConverterList.length;
664                 for (idx = convStart; idx < convLimit; idx++) {
665                     listOffset = gTaggedAliasArray[idx];
666                     if (listOffset != 0 && isAliasInList(alias, listOffset)) {
667                         return idx - convStart;
668                     }
669                 }
670                 /* The standard doesn't know about the alias */
671             }
672             /* else no canonical name */
673         }
674         /* else converter or tag not found */
675 
676         return Integer.MAX_VALUE;
677     }
678 
679     // static U_INLINE UBool isAliasInList(const char *alias, uint32_t
680     // listOffset)
isAliasInList(String alias, int listOffset)681     private static boolean isAliasInList(String alias, int listOffset) {
682         if (listOffset != 0) {
683             int currAlias;
684             int listCount = gTaggedAliasLists[listOffset];
685             /* +1 to skip listCount */
686             int currListArrayIndex = listOffset + 1;
687             for (currAlias = 0; currAlias < listCount; currAlias++) {
688                 if (gTaggedAliasLists[currAlias + currListArrayIndex] != 0
689                         && compareNames(
690                                 alias,
691                                 GET_STRING(gTaggedAliasLists[currAlias + currListArrayIndex])) == 0) {
692                     return true;
693                 }
694             }
695         }
696         return false;
697     }
698 
699     // begin bld.c
700     static String[] gAvailableConverters = null;
701 
702     static int gAvailableConverterCount = 0;
703 
704     static String gDefaultConverterName = null;
705 
706     // static UBool haveAvailableConverterList(UErrorCode *pErrorCode)
haveAvailableConverterList()707     static boolean haveAvailableConverterList() throws IOException{
708         if (gAvailableConverters == null) {
709             int idx;
710             int localConverterCount;
711             String converterName;
712             String[] localConverterList;
713 
714             if (!haveAliasData()) {
715                 return false;
716             }
717 
718             /* We can't have more than "*converterTable" converters to open */
719             localConverterList = new String[gConverterList.length];
720 
721             localConverterCount = 0;
722 
723             for (idx = 0; idx < gConverterList.length; idx++) {
724                 converterName = GET_STRING(gConverterList[idx]);
725                 //UConverter cnv = UConverter.open(converterName);
726                 //TODO: Fix me
727                 localConverterList[localConverterCount++] = converterName;
728 
729             }
730 
731             // agljport:todo umtx_lock(NULL);
732             if (gAvailableConverters == null) {
733                 gAvailableConverters = localConverterList;
734                 gAvailableConverterCount = localConverterCount;
735                 /* haveData should have already registered the cleanup function */
736             } else {
737                 // agljport:todo free((char **)localConverterList);
738             }
739             // agljport:todo umtx_unlock(NULL);
740         }
741         return true;
742     }
743 
744     // U_CFUNC uint16_t bld_countAvailableConverters(UErrorCode *pErrorCode)
bld_countAvailableConverters()745     static int bld_countAvailableConverters() throws IOException{
746         if (haveAvailableConverterList()) {
747             return gAvailableConverterCount;
748         }
749         return 0;
750     }
751 
752     // U_CFUNC const char * bld_getAvailableConverter(uint16_t n, UErrorCode
753     // *pErrorCode)
bld_getAvailableConverter(int n)754     static String bld_getAvailableConverter(int n) throws IOException{
755         if (haveAvailableConverterList()) {
756             if (n < gAvailableConverterCount) {
757                 return gAvailableConverters[n];
758             }
759         }
760         return null;
761     }
762 }
763