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