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