1 10 11 package com.ibm.icu.text; 12 13 import com.ibm.icu.util.CaseInsensitiveString; 14 import com.ibm.icu.impl.Utility; 15 import java.text.ParsePosition ; 16 import java.util.Hashtable ; 17 import java.util.Vector ; 18 19 41 class TransliteratorIDParser { 42 43 private static final char ID_DELIM = ';'; 44 45 private static final char TARGET_SEP = '-'; 46 47 private static final char VARIANT_SEP = '/'; 48 49 private static final char OPEN_REV = '('; 50 51 private static final char CLOSE_REV = ')'; 52 53 private static final String ANY = "Any"; 54 55 private static final int FORWARD = Transliterator.FORWARD; 56 57 private static final int REVERSE = Transliterator.REVERSE; 58 59 private static final Hashtable SPECIAL_INVERSES = new Hashtable (); 60 61 75 private static class Specs { 76 public String source; public String target; public String variant; public String filter; public boolean sawSource; 81 Specs(String s, String t, String v, boolean sawS, String f) { 82 source = s; 83 target = t; 84 variant = v; 85 sawSource = sawS; 86 filter = f; 87 } 88 } 89 90 105 static class SingleID { 106 public String canonID; 107 public String basicID; 108 public String filter; 109 SingleID(String c, String b, String f) { 110 canonID = c; 111 basicID = b; 112 filter = f; 113 } 114 SingleID(String c, String b) { 115 this(c, b, null); 116 } 117 Transliterator getInstance() { 118 Transliterator t; 119 if (basicID == null || basicID.length() == 0) { 120 t = Transliterator.getBasicInstance("Any-Null", canonID); 121 } else { 122 t = Transliterator.getBasicInstance(basicID, canonID); 123 } 124 if (t != null) { 125 if (filter != null) { 126 t.setFilter(new UnicodeSet(filter)); 127 } 128 } 129 return t; 130 } 131 } 132 133 142 public static SingleID parseFilterID(String id, int[] pos) { 143 144 int start = pos[0]; 145 Specs specs = parseFilterID(id, pos, true); 146 if (specs == null) { 147 pos[0] = start; 148 return null; 149 } 150 151 SingleID single = specsToID(specs, FORWARD); 153 single.filter = specs.filter; 154 return single; 155 } 156 157 169 public static SingleID parseSingleID(String id, int[] pos, int dir) { 170 171 int start = pos[0]; 172 173 Specs specsA = null; 176 Specs specsB = null; 177 boolean sawParen = false; 178 179 for (int pass=1; pass<=2; ++pass) { 182 if (pass == 2) { 183 specsA = parseFilterID(id, pos, true); 184 if (specsA == null) { 185 pos[0] = start; 186 return null; 187 } 188 } 189 if (Utility.parseChar(id, pos, OPEN_REV)) { 190 sawParen = true; 191 if (!Utility.parseChar(id, pos, CLOSE_REV)) { 192 specsB = parseFilterID(id, pos, true); 193 if (specsB == null || !Utility.parseChar(id, pos, CLOSE_REV)) { 195 pos[0] = start; 196 return null; 197 } 198 } 199 break; 200 } 201 } 202 203 SingleID single; 205 if (sawParen) { 206 if (dir == FORWARD) { 207 single = specsToID(specsA, FORWARD); 208 single.canonID = single.canonID + 209 OPEN_REV + specsToID(specsB, FORWARD).canonID + CLOSE_REV; 210 if (specsA != null) { 211 single.filter = specsA.filter; 212 } 213 } else { 214 single = specsToID(specsB, FORWARD); 215 single.canonID = single.canonID + 216 OPEN_REV + specsToID(specsA, FORWARD).canonID + CLOSE_REV; 217 if (specsB != null) { 218 single.filter = specsB.filter; 219 } 220 } 221 } else { 222 if (dir == FORWARD) { 224 single = specsToID(specsA, FORWARD); 225 } else { 226 single = specsToSpecialInverse(specsA); 227 if (single == null) { 228 single = specsToID(specsA, REVERSE); 229 } 230 } 231 single.filter = specsA.filter; 232 } 233 234 return single; 235 } 236 237 259 public static UnicodeSet parseGlobalFilter(String id, int[] pos, int dir, 260 int[] withParens, 261 StringBuffer canonID) { 262 UnicodeSet filter = null; 263 int start = pos[0]; 264 265 if (withParens[0] == -1) { 266 withParens[0] = Utility.parseChar(id, pos, OPEN_REV) ? 1 : 0; 267 } else if (withParens[0] == 1) { 268 if (!Utility.parseChar(id, pos, OPEN_REV)) { 269 pos[0] = start; 270 return null; 271 } 272 } 273 274 Utility.skipWhitespace(id, pos); 275 276 if (UnicodeSet.resemblesPattern(id, pos[0])) { 277 ParsePosition ppos = new ParsePosition (pos[0]); 278 try { 279 filter = new UnicodeSet(id, ppos, null); 280 } catch (IllegalArgumentException e) { 281 pos[0] = start; 282 return null; 283 } 284 285 String pattern = id.substring(pos[0], ppos.getIndex()); 286 pos[0] = ppos.getIndex(); 287 288 if (withParens[0] == 1 && !Utility.parseChar(id, pos, CLOSE_REV)) { 289 pos[0] = start; 290 return null; 291 } 292 293 if (canonID != null) { 297 if (dir == FORWARD) { 298 if (withParens[0] == 1) { 299 pattern = String.valueOf(OPEN_REV) + pattern + CLOSE_REV; 300 } 301 canonID.append(pattern + ID_DELIM); 302 } else { 303 if (withParens[0] == 0) { 304 pattern = String.valueOf(OPEN_REV) + pattern + CLOSE_REV; 305 } 306 canonID.insert(0, pattern + ID_DELIM); 307 } 308 } 309 } 310 311 return filter; 312 } 313 314 336 public static boolean parseCompoundID(String id, int dir, 337 StringBuffer canonID, 338 Vector list, 339 UnicodeSet[] globalFilter) { 340 int[] pos = new int[] { 0 }; 341 int[] withParens = new int[1]; 342 list.removeAllElements(); 343 UnicodeSet filter; 344 globalFilter[0] = null; 345 canonID.setLength(0); 346 347 withParens[0] = 0; filter = parseGlobalFilter(id, pos, dir, withParens, canonID); 350 if (filter != null) { 351 if (!Utility.parseChar(id, pos, ID_DELIM)) { 352 canonID.setLength(0); 354 pos[0] = 0; 355 } 356 if (dir == FORWARD) { 357 globalFilter[0] = filter; 358 } 359 } 360 361 boolean sawDelimiter = true; 362 for (;;) { 363 SingleID single = parseSingleID(id, pos, dir); 364 if (single == null) { 365 break; 366 } 367 if (dir == FORWARD) { 368 list.addElement(single); 369 } else { 370 list.insertElementAt(single, 0); 371 } 372 if (!Utility.parseChar(id, pos, ID_DELIM)) { 373 sawDelimiter = false; 374 break; 375 } 376 } 377 378 if (list.size() == 0) { 379 return false; 380 } 381 382 for (int i=0; i<list.size(); ++i) { 384 SingleID single = (SingleID) list.elementAt(i); 385 canonID.append(single.canonID); 386 if (i != (list.size()-1)) { 387 canonID.append(ID_DELIM); 388 } 389 } 390 391 if (sawDelimiter) { 394 withParens[0] = 1; filter = parseGlobalFilter(id, pos, dir, withParens, canonID); 396 if (filter != null) { 397 Utility.parseChar(id, pos, ID_DELIM); 399 400 if (dir == REVERSE) { 401 globalFilter[0] = filter; 402 } 403 } 404 } 405 406 Utility.skipWhitespace(id, pos[0]); 408 if (pos[0] != id.length()) { 409 return false; 410 } 411 412 return true; 413 } 414 415 429 public static void instantiateList(Vector list) { 430 Transliterator t; 431 for (int i=0; i<=list.size(); ) { if (i==list.size()) { 435 break; 436 } 437 438 SingleID single = (SingleID) list.elementAt(i); 439 if (single.basicID.length() == 0) { 440 list.removeElementAt(i); 441 } else { 442 t = single.getInstance(); 443 if (t == null) { 444 t = single.getInstance(); 445 throw new IllegalArgumentException ("Illegal ID " + single.canonID); 446 } 447 list.setElementAt(t, i); 448 ++i; 449 } 450 } 451 452 if (list.size() == 0) { 454 t = Transliterator.getBasicInstance("Any-Null", null); 455 if (t == null) { 456 throw new IllegalArgumentException ("Internal error; cannot instantiate Any-Null"); 458 } 459 list.addElement(t); 460 } 461 } 462 463 474 public static String [] IDtoSTV(String id) { 475 String source = ANY; 476 String target = null; 477 String variant = ""; 478 479 int sep = id.indexOf(TARGET_SEP); 480 int var = id.indexOf(VARIANT_SEP); 481 if (var < 0) { 482 var = id.length(); 483 } 484 boolean isSourcePresent = false; 485 486 if (sep < 0) { 487 target = id.substring(0, var); 489 variant = id.substring(var); 490 } else if (sep < var) { 491 if (sep > 0) { 493 source = id.substring(0, sep); 494 isSourcePresent = true; 495 } 496 target = id.substring(++sep, var); 497 variant = id.substring(var); 498 } else { 499 if (var > 0) { 501 source = id.substring(0, var); 502 isSourcePresent = true; 503 } 504 variant = id.substring(var, sep++); 505 target = id.substring(sep); 506 } 507 508 if (variant.length() > 0) { 509 variant = variant.substring(1); 510 } 511 512 return new String [] { source, target, variant, 513 isSourcePresent ? "" : null }; 514 } 515 516 521 public static String STVtoID(String source, 522 String target, 523 String variant) { 524 StringBuffer id = new StringBuffer (source); 525 if (id.length() == 0) { 526 id.append(ANY); 527 } 528 id.append(TARGET_SEP).append(target); 529 if (variant != null && variant.length() != 0) { 530 id.append(VARIANT_SEP).append(variant); 531 } 532 return id.toString(); 533 } 534 535 567 public static void registerSpecialInverse(String target, 568 String inverseTarget, 569 boolean bidirectional) { 570 SPECIAL_INVERSES.put(new CaseInsensitiveString(target), inverseTarget); 571 if (bidirectional && !target.equalsIgnoreCase(inverseTarget)) { 572 SPECIAL_INVERSES.put(new CaseInsensitiveString(inverseTarget), target); 573 } 574 } 575 576 580 599 private static Specs parseFilterID(String id, int[] pos, 600 boolean allowFilter) { 601 String first = null; 602 String source = null; 603 String target = null; 604 String variant = null; 605 String filter = null; 606 char delimiter = 0; 607 int specCount = 0; 608 int start = pos[0]; 609 610 for (;;) { 614 Utility.skipWhitespace(id, pos); 615 if (pos[0] == id.length()) { 616 break; 617 } 618 619 if (allowFilter && filter == null && 621 UnicodeSet.resemblesPattern(id, pos[0])) { 622 623 ParsePosition ppos = new ParsePosition (pos[0]); 624 UnicodeSet set = new UnicodeSet(id, ppos, null); 625 filter = id.substring(pos[0], ppos.getIndex()); 626 pos[0] = ppos.getIndex(); 627 continue; 628 } 629 630 if (delimiter == 0) { 631 char c = id.charAt(pos[0]); 632 if ((c == TARGET_SEP && target == null) || 633 (c == VARIANT_SEP && variant == null)) { 634 delimiter = c; 635 ++pos[0]; 636 continue; 637 } 638 } 639 640 if (delimiter == 0 && specCount > 0) { 644 break; 645 } 646 647 String spec = Utility.parseUnicodeIdentifier(id, pos); 648 if (spec == null) { 649 break; 653 } 654 655 switch (delimiter) { 656 case 0: 657 first = spec; 658 break; 659 case TARGET_SEP: 660 target = spec; 661 break; 662 case VARIANT_SEP: 663 variant = spec; 664 break; 665 } 666 ++specCount; 667 delimiter = 0; 668 } 669 670 if (first != null) { 673 if (target == null) { 674 target = first; 675 } else { 676 source = first; 677 } 678 } 679 680 if (source == null && target == null) { 682 pos[0] = start; 683 return null; 684 } 685 686 boolean sawSource = true; 688 if (source == null) { 689 source = ANY; 690 sawSource = false; 691 } 692 if (target == null) { 693 target = ANY; 694 } 695 696 return new Specs(source, target, variant, sawSource, filter); 697 } 698 699 706 private static SingleID specsToID(Specs specs, int dir) { 707 String canonID = ""; 708 String basicID = ""; 709 String basicPrefix = ""; 710 if (specs != null) { 711 StringBuffer buf = new StringBuffer (); 712 if (dir == FORWARD) { 713 if (specs.sawSource) { 714 buf.append(specs.source).append(TARGET_SEP); 715 } else { 716 basicPrefix = specs.source + TARGET_SEP; 717 } 718 buf.append(specs.target); 719 } else { 720 buf.append(specs.target).append(TARGET_SEP).append(specs.source); 721 } 722 if (specs.variant != null) { 723 buf.append(VARIANT_SEP).append(specs.variant); 724 } 725 basicID = basicPrefix + buf.toString(); 726 if (specs.filter != null) { 727 buf.insert(0, specs.filter); 728 } 729 canonID = buf.toString(); 730 } 731 return new SingleID(canonID, basicID); 732 } 733 734 741 private static SingleID specsToSpecialInverse(Specs specs) { 742 if (!specs.source.equalsIgnoreCase(ANY)) { 743 return null; 744 } 745 String inverseTarget = (String ) SPECIAL_INVERSES.get( 746 new CaseInsensitiveString(specs.target)); 747 if (inverseTarget != null) { 748 StringBuffer buf = new StringBuffer (); 752 if (specs.filter != null) { 753 buf.append(specs.filter); 754 } 755 if (specs.sawSource) { 756 buf.append(ANY).append(TARGET_SEP); 757 } 758 buf.append(inverseTarget); 759 760 String basicID = ANY + TARGET_SEP + inverseTarget; 761 762 if (specs.variant != null) { 763 buf.append(VARIANT_SEP).append(specs.variant); 764 basicID = basicID + VARIANT_SEP + specs.variant; 765 } 766 return new SingleID(buf.toString(), basicID); 767 } 768 return null; 769 } 770 } 771 772 | Popular Tags |