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 GET_STRING(int idx)50 static final String GET_STRING(int idx) { 51 return extractString(gStringTable, 2 * idx); 52 } 53 GET_NORMALIZED_STRING(int idx)54 private static final String GET_NORMALIZED_STRING(int idx) { 55 return extractString(gNormalizedStringTable, 2 * idx); 56 } 57 extractString(byte[] sArray, int sBegin)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 strlen(byte[] sArray, int sBegin)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 isAlias(String alias)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 haveAliasData()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) findConverter(String alias, boolean[] isAmbigous)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 */ stripForCompare(StringBuilder dst, String name)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 GET_CHAR_TYPE(char c)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 */ io_stripASCIIForCompare(StringBuilder dst, String name)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 */ compareNames(String name1, String name2)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 io_countAliases(String alias)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) io_getAlias(String alias, int n)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) getStandardName(String alias, String standard)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) countAliases(String alias)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) getAlias(String alias, int n)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 */ getAvailableName(int n)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) { getCanonicalName(String alias, String standard)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 } countAvailable()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) getTagNumber(String 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) findTaggedAliasListsOffset(String alias, String standard)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) findTaggedConverterNum(String alias, String standard)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) isAliasInList(String alias, int 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) haveAvailableConverterList()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) bld_countAvailableConverters()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) bld_getAvailableConverter(int n)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