2 *******************************************************************************
\r
3 * Copyright (C) 2006-2007, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 *******************************************************************************
\r
9 package com.ibm.icu.charset;
\r
11 import java.io.IOException;
\r
12 import java.io.BufferedInputStream;
\r
13 import java.io.InputStream;
\r
14 import java.nio.ByteBuffer;
\r
16 import com.ibm.icu.impl.ICUData;
\r
17 import com.ibm.icu.impl.ICUResourceBundle;
\r
19 final class UConverterAlias {
\r
20 static final int UNNORMALIZED = 0;
\r
22 static final int STD_NORMALIZED = 1;
\r
24 static final int AMBIGUOUS_ALIAS_MAP_BIT = 0x8000;
\r
26 static final int CONTAINS_OPTION_BIT = 0x4000;
\r
28 static final int CONVERTER_INDEX_MASK = 0xFFF;
\r
30 static final int NUM_RESERVED_TAGS = 2;
\r
32 static final int NUM_HIDDEN_TAGS = 1;
\r
34 static int[] gConverterList = null;
\r
36 static int[] gTagList = null;
\r
38 static int[] gAliasList = null;
\r
40 static int[] gUntaggedConvArray = null;
\r
42 static int[] gTaggedAliasArray = null;
\r
44 static int[] gTaggedAliasLists = null;
\r
46 static int[] gOptionTable = null;
\r
48 static byte[] gStringTable = null;
\r
50 static byte[] gNormalizedStringTable = null;
\r
52 static final String GET_STRING(int idx) {
\r
53 return new String(gStringTable, 2 * idx, (int) strlen(gStringTable, 2 * idx));
\r
56 private static final String GET_NORMALIZED_STRING(int idx) {
\r
57 return new String(gNormalizedStringTable, 2 * idx, (int) strlen(gNormalizedStringTable, 2 * idx));
\r
60 public static final int strlen(byte[] sArray, int sBegin)
\r
63 while(i < sArray.length && sArray[i++] != 0) {}
\r
64 return i - sBegin - 1;
\r
67 /*private*/ static final int tocLengthIndex = 0;
\r
69 private static final int converterListIndex = 1;
\r
71 private static final int tagListIndex = 2;
\r
73 private static final int aliasListIndex = 3;
\r
75 private static final int untaggedConvArrayIndex = 4;
\r
77 private static final int taggedAliasArrayIndex = 5;
\r
79 private static final int taggedAliasListsIndex = 6;
\r
81 private static final int optionTableIndex = 7;
\r
83 private static final int stringTableIndex = 8;
\r
85 private static final int normalizedStringTableIndex = 9;
\r
87 private static final int minTocLength = 9; /*
\r
88 * min. tocLength in the file,
\r
89 * does not count the
\r
93 private static final int offsetsCount = minTocLength + 1; /*
\r
100 static ByteBuffer gAliasData = null;
\r
102 private static final boolean isAlias(String alias) {
\r
103 if (alias == null) {
\r
104 throw new IllegalArgumentException("Alias param is null!");
\r
106 return (alias.length() != 0);
\r
109 private static final String CNVALIAS_DATA_FILE_NAME = ICUResourceBundle.ICU_BUNDLE + "/cnvalias.icu";
\r
112 * Default buffer size of datafile
\r
114 private static final int CNVALIAS_DATA_BUFFER_SIZE = 25000;
\r
116 private static final synchronized boolean haveAliasData()
\r
117 throws IOException{
\r
120 // agljport:todo umtx_lock(NULL);
\r
121 needInit = gAliasData == null;
\r
123 /* load converter alias data from file if necessary */
\r
125 ByteBuffer data = null;
\r
126 int[] tableArray = null;
\r
128 //byte[] reservedBytes = null;
\r
130 InputStream i = ICUData.getRequiredStream(CNVALIAS_DATA_FILE_NAME);
\r
131 BufferedInputStream b = new BufferedInputStream(i, CNVALIAS_DATA_BUFFER_SIZE);
\r
132 UConverterAliasDataReader reader = new UConverterAliasDataReader(b);
\r
133 tableArray = reader.readToc(offsetsCount);
\r
135 tableStart = tableArray[0];
\r
136 if (tableStart < minTocLength) {
\r
137 throw new IOException("Invalid data format.");
\r
139 gConverterList = new int[(int)tableArray[converterListIndex]];
\r
140 gTagList= new int[(int)tableArray[tagListIndex]];
\r
141 gAliasList = new int[(int)tableArray[aliasListIndex]];
\r
142 gUntaggedConvArray = new int[(int)tableArray[untaggedConvArrayIndex]];
\r
143 gTaggedAliasArray = new int[(int)tableArray[taggedAliasArrayIndex]];
\r
144 gTaggedAliasLists = new int[(int)tableArray[taggedAliasListsIndex]];
\r
145 gOptionTable = new int[(int)tableArray[optionTableIndex]];
\r
146 gStringTable = new byte[(int)tableArray[stringTableIndex]*2];
\r
147 gNormalizedStringTable = new byte[(int)tableArray[normalizedStringTableIndex]*2];
\r
149 reader.read(gConverterList, gTagList,
\r
150 gAliasList, gUntaggedConvArray,
\r
151 gTaggedAliasArray, gTaggedAliasLists,
\r
152 gOptionTable, gStringTable, gNormalizedStringTable);
\r
153 data = ByteBuffer.allocate(0); // dummy UDataMemory object in absence
\r
154 // of memory mapping
\r
156 if (gOptionTable[0] != STD_NORMALIZED) {
\r
157 throw new IOException("Unsupported alias normalization");
\r
160 // agljport:todo umtx_lock(NULL);
\r
161 if (gAliasData == null) {
\r
165 // agljport:fix ucln_common_registerCleanup(UCLN_COMMON_IO,
\r
168 // agljport:todo umtx_unlock(NULL);
\r
170 /* if a different thread set it first, then close the extra data */
\r
171 if (data != null) {
\r
172 // agljport:fix udata_close(data); /* NULL if it was set
\r
180 // U_CFUNC const char * io_getConverterName(const char *alias, UErrorCode
\r
182 // public static final String io_getConverterName(String alias)
\r
183 // throws IOException{
\r
184 // if (haveAliasData() && isAlias(alias)) {
\r
185 // boolean[] isAmbigous = new boolean[1];
\r
186 // int convNum = findConverter(alias, isAmbigous);
\r
187 // if (convNum < gConverterList.length) {
\r
188 // return GET_STRING(gConverterList[(int) convNum]);
\r
190 // /* else converter not found */
\r
196 * search for an alias return the converter number index for gConverterList
\r
198 // static U_INLINE uint32_t findConverter(const char *alias, UErrorCode
\r
200 private static final int findConverter(String alias, boolean[] isAmbigous) {
\r
201 int mid, start, limit;
\r
204 StringBuffer strippedName = new StringBuffer();
\r
205 String aliasToCompare;
\r
207 stripForCompare(strippedName, alias);
\r
208 alias = strippedName.toString();
\r
210 /* do a binary search for the alias */
\r
212 limit = gUntaggedConvArray.length;
\r
214 lastMid = Integer.MAX_VALUE;
\r
217 mid = (start + limit) / 2;
\r
218 if (lastMid == mid) { /* Have we moved? */
\r
219 break; /* We haven't moved, and it wasn't found. */
\r
222 aliasToCompare = GET_NORMALIZED_STRING(gAliasList[(int) mid]);
\r
223 result = alias.compareTo(aliasToCompare);
\r
227 } else if (result > 0) {
\r
231 * Since the gencnval tool folds duplicates into one entry, this
\r
232 * alias in gAliasList is unique, but different standards may
\r
233 * map an alias to different converters.
\r
235 if ((gUntaggedConvArray[(int) mid] & AMBIGUOUS_ALIAS_MAP_BIT) != 0) {
\r
236 isAmbigous[0]=true;
\r
238 /* State whether the canonical converter name contains an option.
\r
239 This information is contained in this list in order to maintain backward & forward compatibility. */
\r
240 /*if (containsOption) {
\r
241 UBool containsCnvOptionInfo = (UBool)gMainTable.optionTable->containsCnvOptionInfo;
\r
242 *containsOption = (UBool)((containsCnvOptionInfo
\r
243 && ((gMainTable.untaggedConvArray[mid] & UCNV_CONTAINS_OPTION_BIT) != 0))
\r
244 || !containsCnvOptionInfo);
\r
246 return gUntaggedConvArray[(int) mid] & CONVERTER_INDEX_MASK;
\r
249 return Integer.MAX_VALUE;
\r
253 * stripForCompare Remove the underscores, dashes and spaces from
\r
254 * the name, and convert the name to lower case.
\r
256 * @param dst The destination buffer, which is <= the buffer of name.
\r
257 * @param name The alias to strip
\r
258 * @return the destination buffer.
\r
260 public static final StringBuffer stripForCompare(StringBuffer dst, String name) {
\r
261 return io_stripASCIIForCompare(dst, name);
\r
265 private static final byte IGNORE = 0;
\r
266 private static final byte ZERO = 1;
\r
267 private static final byte NONZERO = 2;
\r
268 static final byte MINLETTER = 3; /* any values from here on are lowercase letter mappings */
\r
271 /* character types for ASCII 00..7F */
\r
272 static final byte asciiTypes[] = new byte[] {
\r
273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
\r
274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
\r
275 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
\r
276 ZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, 0, 0, 0, 0, 0, 0,
\r
277 0, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
\r
278 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0, 0, 0, 0, 0,
\r
279 0, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
\r
280 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0, 0, 0, 0, 0
\r
283 private static final char GET_CHAR_TYPE(char c) {
\r
284 return (char)((c < asciiTypes.length) ? asciiTypes[c] : (char)IGNORE);
\r
287 /** @see UConverterAlias#compareNames */
\r
288 private static final StringBuffer io_stripASCIIForCompare(StringBuffer dst, String name) {
\r
290 char type, nextType;
\r
292 boolean afterDigit = false;
\r
294 while (nameIndex < name.length()) {
\r
295 c1 = name.charAt(nameIndex++);
\r
296 type = GET_CHAR_TYPE(c1);
\r
299 afterDigit = false;
\r
300 continue; /* ignore all but letters and digits */
\r
302 if (!afterDigit && nameIndex < name.length()) {
\r
303 nextType = GET_CHAR_TYPE(name.charAt(nameIndex));
\r
304 if (nextType == ZERO || nextType == NONZERO) {
\r
305 continue; /* ignore leading zero before another digit */
\r
313 c1 = (char)type; /* lowercased letter */
\r
314 afterDigit = false;
\r
323 * Do a fuzzy compare of a two converter/alias names. The comparison is
\r
324 * case-insensitive. It also ignores the characters '-', '_', and ' ' (dash,
\r
325 * underscore, and space). Thus the strings "UTF-8", "utf_8", and "Utf 8"
\r
326 * are exactly equivalent.
\r
328 * This is a symmetrical (commutative) operation; order of arguments is
\r
329 * insignificant. This is an important property for sorting the list (when
\r
330 * the list is preprocessed into binary form) and for performing binary
\r
331 * searches on it at run time.
\r
334 * a converter name or alias, zero-terminated
\r
336 * a converter name or alias, zero-terminated
\r
337 * @return 0 if the names match, or a negative value if the name1 lexically
\r
338 * precedes name2, or a positive value if the name1 lexically
\r
341 * @see UConverterAlias#stripForCompare
\r
343 static int compareNames(String name1, String name2){
\r
344 int rc, name1Index = 0, name2Index = 0;
\r
345 char type, nextType;
\r
346 char c1 = 0, c2 = 0;
\r
347 boolean afterDigit1 = false, afterDigit2 = false;
\r
350 while (name1Index < name1.length()) {
\r
351 c1 = name1.charAt(name1Index++);
\r
352 type = GET_CHAR_TYPE(c1);
\r
355 afterDigit1 = false;
\r
356 continue; /* ignore all but letters and digits */
\r
358 if (!afterDigit1 && name1Index < name1.length()) {
\r
359 nextType = GET_CHAR_TYPE(name1.charAt(name1Index));
\r
360 if (nextType == ZERO || nextType == NONZERO) {
\r
361 continue; /* ignore leading zero before another digit */
\r
366 afterDigit1 = true;
\r
369 c1 = (char)type; /* lowercased letter */
\r
370 afterDigit1 = false;
\r
373 break; /* deliver c1 */
\r
375 while (name2Index < name2.length()) {
\r
376 c2 = name2.charAt(name2Index++);
\r
377 type = GET_CHAR_TYPE(c2);
\r
380 afterDigit2 = false;
\r
381 continue; /* ignore all but letters and digits */
\r
383 if (!afterDigit2 && name1Index < name1.length()) {
\r
384 nextType = GET_CHAR_TYPE(name2.charAt(name2Index));
\r
385 if (nextType == ZERO || nextType == NONZERO) {
\r
386 continue; /* ignore leading zero before another digit */
\r
391 afterDigit2 = true;
\r
394 c2 = (char)type; /* lowercased letter */
\r
395 afterDigit2 = false;
\r
398 break; /* deliver c2 */
\r
401 /* If we reach the ends of both strings then they match */
\r
402 if (name1Index >= name1.length() && name2Index >= name2.length()) {
\r
406 /* Case-insensitive comparison */
\r
407 rc = (int)c1 - (int)c2;
\r
414 static int io_countAliases(String alias)
\r
415 throws IOException{
\r
416 if (haveAliasData() && isAlias(alias)) {
\r
417 boolean[] isAmbigous = new boolean[1];
\r
418 int convNum = findConverter(alias, isAmbigous);
\r
419 if (convNum < gConverterList.length) {
\r
420 /* tagListNum - 1 is the ALL tag */
\r
421 int listOffset = gTaggedAliasArray[(int) ((gTagList.length - 1)
\r
422 * gConverterList.length + convNum)];
\r
424 if (listOffset != 0) {
\r
425 return gTaggedAliasLists[listOffset];
\r
427 /* else this shouldn't happen. internal program error */
\r
429 /* else converter not found */
\r
435 * Return the number of all aliases (and converter names).
\r
437 * @return the number of all aliases
\r
439 // U_CFUNC uint16_t io_countTotalAliases(UErrorCode *pErrorCode);
\r
440 // static int io_countTotalAliases() throws IOException{
\r
441 // if (haveAliasData()) {
\r
442 // return (int) gAliasList.length;
\r
447 // U_CFUNC const char * io_getAlias(const char *alias, uint16_t n,
\r
448 // UErrorCode *pErrorCode)
\r
449 static String io_getAlias(String alias, int n) throws IOException{
\r
450 if (haveAliasData() && isAlias(alias)) {
\r
451 boolean[] isAmbigous = new boolean[1];
\r
452 int convNum = findConverter(alias,isAmbigous);
\r
453 if (convNum < gConverterList.length) {
\r
454 /* tagListNum - 1 is the ALL tag */
\r
455 int listOffset = gTaggedAliasArray[(int) ((gTagList.length - 1)
\r
456 * gConverterList.length + convNum)];
\r
458 if (listOffset != 0) {
\r
459 //int listCount = gTaggedAliasListsArray[listOffset];
\r
460 /* +1 to skip listCount */
\r
461 int[] currListArray = gTaggedAliasLists;
\r
462 int currListArrayIndex = listOffset + 1;
\r
464 return GET_STRING(currListArray[currListArrayIndex + n]);
\r
467 /* else this shouldn't happen. internal program error */
\r
469 /* else converter not found */
\r
474 // U_CFUNC uint16_t io_countStandards(UErrorCode *pErrorCode) {
\r
475 // static int io_countStandards() throws IOException{
\r
476 // if (haveAliasData()) {
\r
477 // return (int) (gTagList.length - NUM_HIDDEN_TAGS);
\r
482 // U_CAPI const char * U_EXPORT2getStandard(uint16_t n, UErrorCode
\r
484 // static String getStandard(int n) throws IOException{
\r
485 // if (haveAliasData()) {
\r
486 // return GET_STRING(gTagList[n]);
\r
491 // U_CAPI const char * U_EXPORT2 getStandardName(const char *alias, const
\r
492 // char *standard, UErrorCode *pErrorCode)
\r
493 static final String getStandardName(String alias, String standard)throws IOException {
\r
494 if (haveAliasData() && isAlias(alias)) {
\r
495 int listOffset = findTaggedAliasListsOffset(alias, standard);
\r
497 if (0 < listOffset && listOffset < gTaggedAliasLists.length) {
\r
498 int[] currListArray = gTaggedAliasLists;
\r
499 int currListArrayIndex = listOffset + 1;
\r
500 if (currListArray[0] != 0) {
\r
501 return GET_STRING(currListArray[(int) currListArrayIndex]);
\r
508 // U_CAPI uint16_t U_EXPORT2 countAliases(const char *alias, UErrorCode
\r
510 static int countAliases(String alias) throws IOException{
\r
511 return io_countAliases(alias);
\r
514 // U_CAPI const char* U_EXPORT2 getAlias(const char *alias, uint16_t n,
\r
515 // UErrorCode *pErrorCode)
\r
516 static String getAlias(String alias, int n) throws IOException{
\r
517 return io_getAlias(alias, n);
\r
520 // U_CFUNC uint16_t countStandards(void)
\r
521 // static int countStandards()throws IOException{
\r
522 // return io_countStandards();
\r
525 /*returns a single Name from the list, will return NULL if out of bounds
\r
527 static String getAvailableName (int n){
\r
529 if (0 <= n && n <= 0xffff) {
\r
530 String name = bld_getAvailableConverter(n);
\r
533 }catch(IOException ex){
\r
534 //throw away exception
\r
538 // U_CAPI const char * U_EXPORT2 getCanonicalName(const char *alias, const
\r
539 // char *standard, UErrorCode *pErrorCode) {
\r
540 static String getCanonicalName(String alias, String standard) throws IOException{
\r
541 if (haveAliasData() && isAlias(alias)) {
\r
542 int convNum = findTaggedConverterNum(alias, standard);
\r
544 if (convNum < gConverterList.length) {
\r
545 return GET_STRING(gConverterList[(int) convNum]);
\r
551 static int countAvailable (){
\r
553 return bld_countAvailableConverters();
\r
554 }catch(IOException ex){
\r
555 //throw away exception
\r
560 // U_CAPI UEnumeration * U_EXPORT2 openStandardNames(const char *convName,
\r
561 // const char *standard, UErrorCode *pErrorCode)
\r
562 /* static final UConverterAliasesEnumeration openStandardNames(String convName, String standard)throws IOException {
\r
563 UConverterAliasesEnumeration aliasEnum = null;
\r
564 if (haveAliasData() && isAlias(convName)) {
\r
565 int listOffset = findTaggedAliasListsOffset(convName, standard);
\r
568 * When listOffset == 0, we want to acknowledge that the converter
\r
569 * name and standard are okay, but there is nothing to enumerate.
\r
571 if (listOffset < gTaggedAliasLists.length) {
\r
573 UConverterAliasesEnumeration.UAliasContext context = new UConverterAliasesEnumeration.UAliasContext(listOffset, 0);
\r
574 aliasEnum = new UConverterAliasesEnumeration();
\r
575 aliasEnum.setContext(context);
\r
577 else converter or tag not found
\r
582 // static uint32_t getTagNumber(const char *tagname)
\r
583 private static int getTagNumber(String tagName) {
\r
584 if (gTagList != null) {
\r
586 for (tagNum = 0; tagNum < gTagList.length; tagNum++) {
\r
587 if (tagName.equals(GET_STRING(gTagList[(int) tagNum]))) {
\r
593 return Integer.MAX_VALUE;
\r
596 // static uint32_t findTaggedAliasListsOffset(const char *alias, const char
\r
597 // *standard, UErrorCode *pErrorCode)
\r
598 private static int findTaggedAliasListsOffset(String alias, String standard) {
\r
602 int tagNum = getTagNumber(standard);
\r
603 boolean[] isAmbigous = new boolean[1];
\r
604 /* Make a quick guess. Hopefully they used a TR22 canonical alias. */
\r
605 convNum = findConverter(alias, isAmbigous);
\r
607 if (tagNum < (gTagList.length - NUM_HIDDEN_TAGS)
\r
608 && convNum < gConverterList.length) {
\r
609 listOffset = gTaggedAliasArray[(int) (tagNum
\r
610 * gConverterList.length + convNum)];
\r
611 if (listOffset != 0
\r
612 && gTaggedAliasLists[(int) listOffset + 1] != 0) {
\r
615 if (isAmbigous[0]==true) {
\r
617 * Uh Oh! They used an ambiguous alias. We have to search the
\r
618 * whole swiss cheese starting at the highest standard affinity.
\r
619 * This may take a while.
\r
622 for (idx = 0; idx < gTaggedAliasArray.length; idx++) {
\r
623 listOffset = gTaggedAliasArray[(int) idx];
\r
624 if (listOffset != 0 && isAliasInList(alias, listOffset)) {
\r
625 int currTagNum = idx / gConverterList.length;
\r
626 int currConvNum = (idx - currTagNum
\r
627 * gConverterList.length);
\r
628 int tempListOffset = gTaggedAliasArray[(int) (tagNum
\r
629 * gConverterList.length + currConvNum)];
\r
630 if (tempListOffset != 0
\r
631 && gTaggedAliasLists[(int) tempListOffset + 1] != 0) {
\r
632 return tempListOffset;
\r
635 * else keep on looking We could speed this up by
\r
636 * starting on the next row because an alias is unique
\r
637 * per row, right now. This would change if alias
\r
638 * versioning appears.
\r
642 /* The standard doesn't know about the alias */
\r
644 /* else no default name */
\r
647 /* else converter or tag not found */
\r
649 return Integer.MAX_VALUE;
\r
652 /* Return the canonical name */
\r
653 // static uint32_t findTaggedConverterNum(const char *alias, const char
\r
654 // *standard, UErrorCode *pErrorCode)
\r
655 private static int findTaggedConverterNum(String alias, String standard) {
\r
659 int tagNum = getTagNumber(standard);
\r
660 boolean[] isAmbigous = new boolean[1];
\r
662 /* Make a quick guess. Hopefully they used a TR22 canonical alias. */
\r
663 convNum = findConverter(alias, isAmbigous);
\r
665 if (tagNum < (gTagList.length - NUM_HIDDEN_TAGS)
\r
666 && convNum < gConverterList.length) {
\r
667 listOffset = gTaggedAliasArray[(int) (tagNum
\r
668 * gConverterList.length + convNum)];
\r
669 if (listOffset != 0 && isAliasInList(alias, listOffset)) {
\r
672 if (isAmbigous[0] == true) {
\r
674 * Uh Oh! They used an ambiguous alias. We have to search one
\r
675 * slice of the swiss cheese. We search only in the requested
\r
676 * tag, not the whole thing. This may take a while.
\r
678 int convStart = (tagNum) * gConverterList.length;
\r
679 int convLimit = (tagNum + 1) * gConverterList.length;
\r
680 for (idx = convStart; idx < convLimit; idx++) {
\r
681 listOffset = gTaggedAliasArray[(int) idx];
\r
682 if (listOffset != 0 && isAliasInList(alias, listOffset)) {
\r
683 return idx - convStart;
\r
686 /* The standard doesn't know about the alias */
\r
688 /* else no canonical name */
\r
690 /* else converter or tag not found */
\r
692 return Integer.MAX_VALUE;
\r
695 // static U_INLINE UBool isAliasInList(const char *alias, uint32_t
\r
697 private static boolean isAliasInList(String alias, int listOffset) {
\r
698 if (listOffset != 0) {
\r
700 int listCount = gTaggedAliasLists[(int) listOffset];
\r
701 /* +1 to skip listCount */
\r
702 int[] currList = gTaggedAliasLists;
\r
703 int currListArrayIndex = listOffset + 1;
\r
704 for (currAlias = 0; currAlias < listCount; currAlias++) {
\r
705 if (currList[(int) (currAlias + currListArrayIndex)] != 0
\r
708 GET_STRING(currList[(int) (currAlias + currListArrayIndex)])) == 0) {
\r
717 static String[] gAvailableConverters = null;
\r
719 static int gAvailableConverterCount = 0;
\r
721 static byte[] gDefaultConverterNameBuffer; // [MAX_CONVERTER_NAME_LENGTH +
\r
722 // 1]; /* +1 for NULL */
\r
724 static String gDefaultConverterName = null;
\r
726 // static UBool haveAvailableConverterList(UErrorCode *pErrorCode)
\r
727 static boolean haveAvailableConverterList() throws IOException{
\r
728 if (gAvailableConverters == null) {
\r
730 int localConverterCount;
\r
731 String converterName;
\r
732 String[] localConverterList;
\r
734 if (!haveAliasData()) {
\r
738 /* We can't have more than "*converterTable" converters to open */
\r
739 localConverterList = new String[(int) gConverterList.length];
\r
741 localConverterCount = 0;
\r
743 for (idx = 0; idx < gConverterList.length; idx++) {
\r
744 converterName = GET_STRING(gConverterList[idx]);
\r
745 //UConverter cnv = UConverter.open(converterName);
\r
747 localConverterList[localConverterCount++] = converterName;
\r
751 // agljport:todo umtx_lock(NULL);
\r
752 if (gAvailableConverters == null) {
\r
753 gAvailableConverters = localConverterList;
\r
754 gAvailableConverterCount = localConverterCount;
\r
755 /* haveData should have already registered the cleanup function */
\r
757 // agljport:todo free((char **)localConverterList);
\r
759 // agljport:todo umtx_unlock(NULL);
\r
764 // U_CFUNC uint16_t bld_countAvailableConverters(UErrorCode *pErrorCode)
\r
765 static int bld_countAvailableConverters() throws IOException{
\r
766 if (haveAvailableConverterList()) {
\r
767 return gAvailableConverterCount;
\r
772 // U_CFUNC const char * bld_getAvailableConverter(uint16_t n, UErrorCode
\r
774 static String bld_getAvailableConverter(int n) throws IOException{
\r
775 if (haveAvailableConverterList()) {
\r
776 if (n < gAvailableConverterCount) {
\r
777 return gAvailableConverters[n];
\r
783 /* default converter name --------------------------------------------------- */
\r
786 * In order to be really thread-safe, the get function would have to take
\r
787 * a buffer parameter and copy the current string inside a mutex block.
\r
788 * This implementation only tries to be really thread-safe while
\r
789 * setting the name.
\r
790 * It assumes that setting a pointer is atomic.
\r
793 // U_CFUNC const char * getDefaultName()
\r
794 // static final synchronized String getDefaultName() {
\r
795 // /* local variable to be thread-safe */
\r
798 // //agljport:todo umtx_lock(null);
\r
799 // name = gDefaultConverterName;
\r
800 // //agljport:todo umtx_unlock(null);
\r
802 // if (name == null) {
\r
803 // //UConverter cnv = null;
\r
806 // name = CharsetICU.getDefaultCharsetName();
\r
808 // /* if the name is there, test it out and get the canonical name with options */
\r
809 // if (name != null) {
\r
810 // // cnv = UConverter.open(name);
\r
811 // // name = cnv.getName(cnv);
\r
815 // if (name == null || name.length() == 0 ||/* cnv == null ||*/
\r
816 // length >= gDefaultConverterNameBuffer.length) {
\r
817 // /* Panic time, let's use a fallback. */
\r
818 // name = new String("US-ASCII");
\r
821 // //length=(int32_t)(strlen(name));
\r
823 // /* Copy the name before we close the converter. */
\r
824 // name = gDefaultConverterName;
\r