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