Home | History | Annotate | Download | only in charset
      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 
     52     private static final String GET_STRING(int idx) {
     53         return extractString(gStringTable, 2 * idx);
     54     }
     55 
     56     private static final String GET_NORMALIZED_STRING(int idx) {
     57         return extractString(gNormalizedStringTable, 2 * idx);
     58     }
     59 
     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 
     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 
    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 
    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)
    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      */
    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 
    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 */
    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      */
    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 
    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)
    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)
    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)
    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)
    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      */
    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) {
    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     }
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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