1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 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 GET_STRING(int idx)52 private static final String GET_STRING(int idx) { 53 return extractString(gStringTable, 2 * idx); 54 } 55 GET_NORMALIZED_STRING(int idx)56 private static final String GET_NORMALIZED_STRING(int idx) { 57 return extractString(gNormalizedStringTable, 2 * idx); 58 } 59 extractString(byte[] sArray, int sBegin)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 strlen(byte[] sArray, int sBegin)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 isAlias(String alias)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 haveAliasData()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) findConverter(String alias, boolean[] isAmbigous)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 */ stripForCompare(StringBuilder dst, String name)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 GET_CHAR_TYPE(char c)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 */ io_stripASCIIForCompare(StringBuilder dst, String name)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 */ compareNames(String name1, String name2)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 io_countAliases(String alias)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) io_getAlias(String alias, int n)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) getStandardName(String alias, String standard)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) countAliases(String alias)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) getAlias(String alias, int n)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 */ getAvailableName(int n)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) { getCanonicalName(String alias, String standard)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 } countAvailable()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) getTagNumber(String 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) findTaggedAliasListsOffset(String alias, String standard)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) findTaggedConverterNum(String alias, String standard)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) isAliasInList(String alias, int 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) haveAvailableConverterList()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) bld_countAvailableConverters()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) bld_getAvailableConverter(int n)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