| 1 package com.thaiopensource.datatype.xsd.regex.jdk1_4; 2 3 import com.thaiopensource.util.Utf16; 4 import com.thaiopensource.util.Localizer; 5 import com.thaiopensource.datatype.xsd.regex.RegexSyntaxException; 6 7 import java.util.Collections ; 8 import java.util.Iterator ; 9 import java.util.List ; 10 import java.util.Vector ; 11 import java.math.BigDecimal ; 12 13 19 public class Translator { 20 private final String regExp; 21 private int pos = 0; 22 private final int length; 23 private char curChar; 24 private boolean eos = false; 25 private final StringBuffer result = new StringBuffer (); 26 27 static private final String categories = "LMNPZSC"; 28 static private final CharClass[] categoryCharClasses = new CharClass[categories.length()]; 29 static private final String subCategories = "LuLlLtLmLoMnMcMeNdNlNoPcPdPsPePiPfPoZsZlZpSmScSkSoCcCfCoCn"; 30 static private final CharClass[] subCategoryCharClasses = new CharClass[subCategories.length() / 2]; 31 32 static private final int NONBMP_MIN = 0x10000; 33 static private final int NONBMP_MAX = 0x10FFFF; 34 static private final char SURROGATE2_MIN = '\uDC00'; 35 static private final char SURROGATE2_MAX = '\uDFFF'; 36 37 static final Localizer localizer = new Localizer(Translator.class); 38 39 static private final String [] blockNames = { 40 "BasicLatin", 41 "Latin-1Supplement", 42 "LatinExtended-A", 43 "LatinExtended-B", 44 "IPAExtensions", 45 "SpacingModifierLetters", 46 "CombiningDiacriticalMarks", 47 "Greek", 48 "Cyrillic", 49 "Armenian", 50 "Hebrew", 51 "Arabic", 52 "Syriac", 53 "Thaana", 54 "Devanagari", 55 "Bengali", 56 "Gurmukhi", 57 "Gujarati", 58 "Oriya", 59 "Tamil", 60 "Telugu", 61 "Kannada", 62 "Malayalam", 63 "Sinhala", 64 "Thai", 65 "Lao", 66 "Tibetan", 67 "Myanmar", 68 "Georgian", 69 "HangulJamo", 70 "Ethiopic", 71 "Cherokee", 72 "UnifiedCanadianAboriginalSyllabics", 73 "Ogham", 74 "Runic", 75 "Khmer", 76 "Mongolian", 77 "LatinExtendedAdditional", 78 "GreekExtended", 79 "GeneralPunctuation", 80 "SuperscriptsandSubscripts", 81 "CurrencySymbols", 82 "CombiningMarksforSymbols", 83 "LetterlikeSymbols", 84 "NumberForms", 85 "Arrows", 86 "MathematicalOperators", 87 "MiscellaneousTechnical", 88 "ControlPictures", 89 "OpticalCharacterRecognition", 90 "EnclosedAlphanumerics", 91 "BoxDrawing", 92 "BlockElements", 93 "GeometricShapes", 94 "MiscellaneousSymbols", 95 "Dingbats", 96 "BraillePatterns", 97 "CJKRadicalsSupplement", 98 "KangxiRadicals", 99 "IdeographicDescriptionCharacters", 100 "CJKSymbolsandPunctuation", 101 "Hiragana", 102 "Katakana", 103 "Bopomofo", 104 "HangulCompatibilityJamo", 105 "Kanbun", 106 "BopomofoExtended", 107 "EnclosedCJKLettersandMonths", 108 "CJKCompatibility", 109 "CJKUnifiedIdeographsExtensionA", 110 "CJKUnifiedIdeographs", 111 "YiSyllables", 112 "YiRadicals", 113 "HangulSyllables", 114 "CJKCompatibilityIdeographs", 117 "AlphabeticPresentationForms", 118 "ArabicPresentationForms-A", 119 "CombiningHalfMarks", 120 "CJKCompatibilityForms", 121 "SmallFormVariants", 122 "ArabicPresentationForms-B", 123 "Specials", 124 "HalfwidthandFullwidthForms", 125 "Specials" 126 }; 127 128 129 132 static private final String [] specialBlockNames = { 133 "OldItalic", 134 "Gothic", 135 "Deseret", 136 "ByzantineMusicalSymbols", 137 "MusicalSymbols", 138 "MathematicalAlphanumericSymbols", 139 "CJKUnifiedIdeographsExtensionB", 140 "CJKCompatibilityIdeographsSupplement", 141 "Tags", 142 "PrivateUse", 143 "HighSurrogates", 144 "HighPrivateUseSurrogates", 145 "LowSurrogates", 146 }; 147 148 151 static private final CharClass[] specialBlockCharClasses = { 152 new CharRange(0x10300, 0x1032F), 153 new CharRange(0x10330, 0x1034F), 154 new CharRange(0x10400, 0x1044F), 155 new CharRange(0x1D000, 0x1D0FF), 156 new CharRange(0x1D100, 0x1D1FF), 157 new CharRange(0x1D400, 0x1D7FF), 158 new CharRange(0x20000, 0x2A6D6), 159 new CharRange(0x2F800, 0x2FA1F), 160 new CharRange(0xE0000, 0xE007F), 161 new Union(new CharClass[] { 162 new CharRange(0xE000, 0xF8FF), 163 new CharRange(0xF0000, 0xFFFFD), 164 new CharRange(0x100000, 0x10FFFD) 165 }), 166 Empty.getInstance(), 167 Empty.getInstance(), 168 Empty.getInstance() 169 }; 170 171 static private final CharClass DOT = new Complement(new Union(new CharClass[] { new SingleChar('\n'), new SingleChar('\r') })); 172 173 static private final CharClass ESC_d = new Property("Nd"); 174 175 static private final CharClass ESC_D = new Complement(ESC_d); 176 177 static private final CharClass ESC_W = new Union(new CharClass[] {new Property("P"), new Property("Z"), new Property("C")}); 178 179 static private final CharClass ESC_w = new Complement(ESC_W); 180 181 static private final CharClass ESC_s = new Union(new CharClass[] { 182 new SingleChar(' '), 183 new SingleChar('\n'), 184 new SingleChar('\r'), 185 new SingleChar('\t') 186 }); 187 188 static private final CharClass ESC_S = new Complement(ESC_s); 189 190 static private final CharClass ESC_i = makeCharClass(NamingExceptions.NMSTRT_CATEGORIES, 191 NamingExceptions.NMSTRT_INCLUDES, 192 NamingExceptions.NMSTRT_EXCLUDE_RANGES); 193 194 static private final CharClass ESC_I = new Complement(ESC_i); 195 196 static private final CharClass ESC_c = makeCharClass(NamingExceptions.NMCHAR_CATEGORIES, 197 NamingExceptions.NMCHAR_INCLUDES, 198 NamingExceptions.NMCHAR_EXCLUDE_RANGES); 199 200 static private final CharClass ESC_C = new Complement(ESC_c); 201 202 static private final char EOS = '\0'; 203 204 private Translator(String regExp) { 205 this.regExp = regExp; 206 this.length = regExp.length(); 207 advance(); 208 } 209 210 225 static public String translate(String regexp) throws RegexSyntaxException { 226 Translator tr = new Translator(regexp); 227 tr.translateTop(); 228 return tr.result.toString(); 229 } 230 231 private void advance() { 232 if (pos < length) 233 curChar = regExp.charAt(pos++); 234 else { 235 pos++; 236 curChar = EOS; 237 eos = true; 238 } 239 } 240 241 private void translateTop() throws RegexSyntaxException { 242 translateRegExp(); 243 if (!eos) 244 throw makeException("expected_eos"); 245 } 246 247 private void translateRegExp() throws RegexSyntaxException { 248 translateBranch(); 249 while (curChar == '|') { 250 copyCurChar(); 251 translateBranch(); 252 } 253 } 254 255 private void translateBranch() throws RegexSyntaxException { 256 while (translateAtom()) 257 translateQuantifier(); 258 } 259 260 private void translateQuantifier() throws RegexSyntaxException { 261 switch (curChar) { 262 case '*': 263 case '?': 264 case '+': 265 copyCurChar(); 266 return; 267 case '{': 268 copyCurChar(); 269 translateQuantity(); 270 expect('}'); 271 copyCurChar(); 272 } 273 } 274 275 private void translateQuantity() throws RegexSyntaxException { 276 String lower = parseQuantExact(); 277 int lowerValue = -1; 278 try { 279 lowerValue = Integer.parseInt(lower); 280 result.append(lower); 281 } 282 catch (NumberFormatException e) { 283 result.append(Integer.MAX_VALUE); 285 } 286 if (curChar == ',') { 287 copyCurChar(); 288 if (curChar != '}') { 289 String upper = parseQuantExact(); 290 try { 291 int upperValue = Integer.parseInt(upper); 292 result.append(upper); 293 if (lowerValue < 0 || upperValue < lowerValue) 294 throw makeException("invalid_quantity_range"); 295 } 296 catch (NumberFormatException e) { 297 result.append(Integer.MAX_VALUE); 298 if (lowerValue < 0 && new BigDecimal (lower).compareTo(new BigDecimal (upper)) > 0) 299 throw makeException("invalid_quantity_range"); 300 } 301 } 302 } 303 } 304 305 private String parseQuantExact() throws RegexSyntaxException { 306 StringBuffer buf = new StringBuffer (); 307 do { 308 if ("0123456789".indexOf(curChar) < 0) 309 throw makeException("expected_digit"); 310 buf.append(curChar); 311 advance(); 312 } while (curChar != ',' && curChar != '}'); 313 return buf.toString(); 314 } 315 316 private void copyCurChar() { 317 result.append(curChar); 318 advance(); 319 } 320 321 static final int NONE = -1; 322 static final int SOME = 0; 323 static final int ALL = 1; 324 325 static final String SURROGATES1_CLASS = "[\uD800-\uDBFF]"; 326 static final String SURROGATES2_CLASS = "[\uDC00-\uDFFF]"; 327 static final String NOT_ALLOWED_CLASS = "[\u0000&&[^\u0000]]"; 328 329 static final class Range implements Comparable { 330 private final int min; 331 private final int max; 332 333 Range(int min, int max) { 334 this.min = min; 335 this.max = max; 336 } 337 338 int getMin() { 339 return min; 340 } 341 342 int getMax() { 343 return max; 344 } 345 346 public int compareTo(Object o) { 347 Range other = (Range)o; 348 if (this.min < other.min) 349 return -1; 350 if (this.min > other.min) 351 return 1; 352 if (this.max > other.max) 353 return -1; 354 if (this.max < other.max) 355 return 1; 356 return 0; 357 } 358 } 359 360 static abstract class CharClass { 361 362 private final int containsBmp; 363 private final int containsNonBmp; 366 367 protected CharClass(int containsBmp, int containsNonBmp) { 368 this.containsBmp = containsBmp; 369 this.containsNonBmp = containsNonBmp; 370 } 371 372 int getContainsBmp() { 373 return containsBmp; 374 } 375 376 int getContainsNonBmp() { 377 return containsNonBmp; 378 } 379 380 final void output(StringBuffer buf) { 381 switch (containsNonBmp) { 382 case NONE: 383 if (containsBmp == NONE) 384 buf.append(NOT_ALLOWED_CLASS); 385 else 386 outputBmp(buf); 387 break; 388 case ALL: 389 buf.append('('); 390 if (containsBmp == NONE) { 391 buf.append(SURROGATES1_CLASS); 392 buf.append(SURROGATES2_CLASS); 393 } 394 else { 395 outputBmp(buf); 396 buf.append(SURROGATES2_CLASS); 397 buf.append('?'); 398 } 399 buf.append(')'); 400 break; 401 case SOME: 402 buf.append('('); 403 boolean needSep = false; 404 if (containsBmp != NONE) { 405 needSep = true; 406 outputBmp(buf); 407 } 408 List ranges = new Vector (); 409 addNonBmpRanges(ranges); 410 sortRangeList(ranges); 411 String hi = highSurrogateRanges(ranges); 412 if (hi.length() > 0) { 413 if (needSep) 414 buf.append('|'); 415 else 416 needSep = true; 417 buf.append('['); 418 for (int i = 0, len = hi.length(); i < len; i += 2) { 419 char min = hi.charAt(i); 420 char max = hi.charAt(i + 1); 421 if (min == max) 422 buf.append(min); 423 else { 424 buf.append(min); 425 buf.append('-'); 426 buf.append(max); 427 } 428 } 429 buf.append(']'); 430 buf.append(SURROGATES2_CLASS); 431 } 432 String lo = lowSurrogateRanges(ranges); 433 for (int i = 0, len = lo.length(); i < len; i += 3) { 434 if (needSep) 435 buf.append('|'); 436 else 437 needSep = true; 438 buf.append(lo.charAt(i)); 439 char min = lo.charAt(i + 1); 440 char max = lo.charAt(i + 2); 441 if (min == max && (i + 3 >= len || lo.charAt(i + 3) != lo.charAt(i))) 442 buf.append(min); 443 else { 444 buf.append('['); 445 for (;;) { 446 if (min == max) 447 buf.append(min); 448 else { 449 buf.append(min); 450 buf.append('-'); 451 buf.append(max); 452 } 453 if (i + 3 >= len || lo.charAt(i + 3) != lo.charAt(i)) 454 break; 455 i += 3; 456 min = lo.charAt(i + 1); 457 max = lo.charAt(i + 2); 458 } 459 buf.append(']'); 460 } 461 } 462 if (!needSep) 463 buf.append(NOT_ALLOWED_CLASS); 464 buf.append(')'); 465 break; 466 } 467 } 468 469 static String highSurrogateRanges(List ranges) { 470 StringBuffer highRanges = new StringBuffer (); 471 for (int i = 0, len = ranges.size(); i < len; i++) { 472 Range r = (Range)ranges.get(i); 473 char min1 = Utf16.surrogate1(r.getMin()); 474 char min2 = Utf16.surrogate2(r.getMin()); 475 char max1 = Utf16.surrogate1(r.getMax()); 476 char max2 = Utf16.surrogate2(r.getMax()); 477 if (min2 != SURROGATE2_MIN) 478 min1++; 479 if (max2 != SURROGATE2_MAX) 480 max1--; 481 if (max1 >= min1) { 482 highRanges.append(min1); 483 highRanges.append(max1); 484 } 485 } 486 return highRanges.toString(); 487 } 488 489 static String lowSurrogateRanges(List ranges) { 490 StringBuffer lowRanges = new StringBuffer (); 491 for (int i = 0, len = ranges.size(); i < len; i++) { 492 Range r = (Range)ranges.get(i); 493 char min1 = Utf16.surrogate1(r.getMin()); 494 char min2 = Utf16.surrogate2(r.getMin()); 495 char max1 = Utf16.surrogate1(r.getMax()); 496 char max2 = Utf16.surrogate2(r.getMax()); 497 if (min1 == max1) { 498 if (min2 != SURROGATE2_MIN || max2 != SURROGATE2_MAX) { 499 lowRanges.append(min1); 500 lowRanges.append(min2); 501 lowRanges.append(max2); 502 } 503 } 504 else { 505 if (min2 != SURROGATE2_MIN) { 506 lowRanges.append(min1); 507 lowRanges.append(min2); 508 lowRanges.append(SURROGATE2_MAX); 509 } 510 if (max2 != SURROGATE2_MAX) { 511 lowRanges.append(max1); 512 lowRanges.append(SURROGATE2_MIN); 513 lowRanges.append(max2); 514 } 515 } 516 } 517 return lowRanges.toString(); 518 } 519 520 abstract void outputBmp(StringBuffer buf); 521 abstract void outputComplementBmp(StringBuffer buf); 522 523 int singleChar() { 524 return -1; 525 } 526 527 void addNonBmpRanges(List ranges) { 528 } 529 530 531 static void sortRangeList(List ranges) { 532 Collections.sort(ranges); 533 int toIndex = 0; 534 int fromIndex = 0; 535 int len = ranges.size(); 536 while (fromIndex < len) { 537 Range r = (Range)ranges.get(fromIndex); 538 int min = r.getMin(); 539 int max = r.getMax(); 540 while (++fromIndex < len) { 541 Range r2 = (Range)ranges.get(fromIndex); 542 if (r2.getMin() > max + 1) 543 break; 544 if (r2.getMax() > max) 545 max = r2.getMax(); 546 } 547 if (max != r.getMax()) 548 r = new Range(min, max); 549 ranges.set(toIndex++, r); 550 } 551 while (len > toIndex) 552 ranges.remove(--len); 553 } 554 555 } 556 557 static abstract class SimpleCharClass extends CharClass { 558 SimpleCharClass(int containsBmp, int containsNonBmp) { 559 super(containsBmp, containsNonBmp); 560 } 561 562 void outputBmp(StringBuffer buf) { 563 buf.append('['); 564 inClassOutputBmp(buf); 565 buf.append(']'); 566 } 567 568 void outputComplementBmp(StringBuffer buf) { 570 if (getContainsBmp() == NONE) 571 buf.append("[\u0000-\uFFFF]"); 572 else { 573 buf.append("[^"); 574 inClassOutputBmp(buf); 575 buf.append(']'); 576 } 577 } 578 abstract void inClassOutputBmp(StringBuffer buf); 579 } 580 581 static class SingleChar extends SimpleCharClass { 582 private final char c; 583 SingleChar(char c) { 584 super(SOME, NONE); 585 this.c = c; 586 } 587 588 int singleChar() { 589 return c; 590 } 591 592 void outputBmp(StringBuffer buf) { 593 inClassOutputBmp(buf); 594 } 595 596 void inClassOutputBmp(StringBuffer buf) { 597 if (isJavaMetaChar(c)) 598 buf.append('\\'); 599 buf.append(c); 600 } 601 602 } 603 604 static class WideSingleChar extends SimpleCharClass { 605 private final int c; 606 607 WideSingleChar(int c) { 608 super(NONE, SOME); 609 this.c = c; 610 } 611 612 void inClassOutputBmp(StringBuffer buf) { 613 throw new RuntimeException ("BMP output botch"); 614 } 615 616 int singleChar() { 617 return c; 618 } 619 620 void addNonBmpRanges(List ranges) { 621 ranges.add(new Range(c, c)); 622 } 623 } 624 625 static class Empty extends SimpleCharClass { 626 static private final Empty instance = new Empty(); 627 private Empty() { 628 super(NONE, NONE); 629 } 630 631 static Empty getInstance() { 632 return instance; 633 } 634 635 void inClassOutputBmp(StringBuffer buf) { 636 throw new RuntimeException ("BMP output botch"); 637 } 638 639 } 640 641 static class CharRange extends SimpleCharClass { 642 private final int lower; 643 private final int upper; 644 645 CharRange(int lower, int upper) { 646 super(lower < NONBMP_MIN ? SOME : NONE, 647 upper >= NONBMP_MIN ? SOME : NONE); 649 this.lower = lower; 650 this.upper = upper; 651 } 652 653 void inClassOutputBmp(StringBuffer buf) { 654 if (lower >= NONBMP_MIN) 655 throw new RuntimeException ("BMP output botch"); 656 if (isJavaMetaChar((char)lower)) 657 buf.append('\\'); 658 buf.append((char)lower); 659 buf.append('-'); 660 if (upper < NONBMP_MIN) { 661 if (isJavaMetaChar((char)upper)) 662 buf.append('\\'); 663 buf.append((char)upper); 664 } 665 else 666 buf.append('\uFFFF'); 667 } 668 669 void addNonBmpRanges(List ranges) { 670 if (upper >= NONBMP_MIN) 671 ranges.add(new Range(lower < NONBMP_MIN ? NONBMP_MIN : lower, upper)); 672 } 673 } 674 675 static class Property extends SimpleCharClass { 676 private final String name; 677 678 Property(String name) { 679 super(SOME, NONE); 680 this.name = name; 681 } 682 683 void outputBmp(StringBuffer buf) { 684 inClassOutputBmp(buf); 685 } 686 687 void inClassOutputBmp(StringBuffer buf) { 688 buf.append("\\p{"); 689 buf.append(name); 690 buf.append('}'); 691 } 692 693 void outputComplementBmp(StringBuffer buf) { 694 buf.append("\\P{"); 695 buf.append(name); 696 buf.append('}'); 697 } 698 } 699 700 static class Subtraction extends CharClass { 701 private final CharClass cc1; 702 private final CharClass cc2; 703 Subtraction(CharClass cc1, CharClass cc2) { 704 super(Math.min(cc1.getContainsBmp(), -cc2.getContainsBmp()), 707 Math.min(cc1.getContainsNonBmp(), -cc2.getContainsNonBmp())); 708 this.cc1 = cc1; 709 this.cc2 = cc2; 710 } 711 712 void outputBmp(StringBuffer buf) { 713 buf.append('['); 714 cc1.outputBmp(buf); 715 buf.append("&&"); 716 cc2.outputComplementBmp(buf); 717 buf.append(']'); 718 } 719 720 void outputComplementBmp(StringBuffer buf) { 721 buf.append('['); 722 cc1.outputComplementBmp(buf); 723 cc2.outputBmp(buf); 724 buf.append(']'); 725 } 726 727 void addNonBmpRanges(List ranges) { 728 List posList = new Vector (); 729 cc1.addNonBmpRanges(posList); 730 List negList = new Vector (); 731 cc2.addNonBmpRanges(negList); 732 sortRangeList(posList); 733 sortRangeList(negList); 734 Iterator negIter = negList.iterator(); 735 Range negRange; 736 if (negIter.hasNext()) 737 negRange = (Range)negIter.next(); 738 else 739 negRange = null; 740 for (int i = 0, len = posList.size(); i < len; i++) { 741 Range posRange = (Range)posList.get(i); 742 while (negRange != null && negRange.getMax() < posRange.getMin()) { 743 if (negIter.hasNext()) 744 negRange = (Range)negIter.next(); 745 else 746 negRange = null; 747 } 748 int min = posRange.getMin(); 750 while (negRange != null && negRange.getMin() <= posRange.getMax()) { 751 if (min < negRange.getMin()) { 752 ranges.add(new Range(min, negRange.getMin() - 1)); 753 } 754 min = negRange.getMax() + 1; 755 if (min > posRange.getMax()) 756 break; 757 if (negIter.hasNext()) 758 negRange = (Range)negIter.next(); 759 else 760 negRange = null; 761 } 762 if (min <= posRange.getMax()) 763 ranges.add(new Range(min, posRange.getMax())); 764 } 765 } 766 } 767 768 static class Union extends CharClass { 769 private final List members; 770 771 Union(CharClass[] v) { 772 this(toList(v)); 773 } 774 775 static private List toList(CharClass[] v) { 776 List members = new Vector (); 777 for (int i = 0; i < v.length; i++) 778 members.add(v[i]); 779 return members; 780 } 781 782 Union(List members) { 783 super(computeContainsBmp(members), computeContainsNonBmp(members)); 784 this.members = members; 785 } 786 787 void outputBmp(StringBuffer buf) { 788 buf.append('['); 789 for (int i = 0, len = members.size(); i < len; i++) { 790 CharClass cc = (CharClass)members.get(i); 791 if (cc.getContainsBmp() != NONE) { 792 if (cc instanceof SimpleCharClass) 793 ((SimpleCharClass)cc).inClassOutputBmp(buf); 794 else 795 cc.outputBmp(buf); 796 } 797 } 798 buf.append(']'); 799 } 800 801 void outputComplementBmp(StringBuffer buf) { 802 boolean first = true; 803 int len = members.size(); 804 for (int i = 0; i < len; i++) { 805 CharClass cc = (CharClass)members.get(i); 806 if (cc.getContainsBmp() != NONE && cc instanceof SimpleCharClass) { 807 if (first) { 808 buf.append("[^"); 809 first = false; 810 } 811 ((SimpleCharClass)cc).inClassOutputBmp(buf); 812 } 813 } 814 for (int i = 0; i < len; i++) { 815 CharClass cc = (CharClass)members.get(i); 816 if (cc.getContainsBmp() != NONE && !(cc instanceof SimpleCharClass)) { 817 if (first) { 818 buf.append('['); 819 first = false; 820 } 821 else 822 buf.append("&&"); 823 cc.outputComplementBmp(buf); 826 } 827 } 828 if (first == true) 829 buf.append("[\u0000-\uFFFF]"); 831 else 832 buf.append(']'); 833 } 834 835 void addNonBmpRanges(List ranges) { 836 for (int i = 0, len = members.size(); i < len; i++) 837 ((CharClass)members.get(i)).addNonBmpRanges(ranges); 838 } 839 840 private static int computeContainsBmp(List members) { 841 int ret = NONE; 842 for (int i = 0, len = members.size(); i < len; i++) 843 ret = Math.max(ret, ((CharClass)members.get(i)).getContainsBmp()); 844 return ret; 845 } 846 847 private static int computeContainsNonBmp(List members) { 848 int ret = NONE; 849 for (int i = 0, len = members.size(); i < len; i++) 850 ret = Math.max(ret, ((CharClass)members.get(i)).getContainsNonBmp()); 851 return ret; 852 } 853 } 854 855 static class Complement extends CharClass { 856 private final CharClass cc; 857 Complement(CharClass cc) { 858 super(-cc.getContainsBmp(), -cc.getContainsNonBmp()); 859 this.cc = cc; 860 } 861 862 void outputBmp(StringBuffer buf) { 863 cc.outputComplementBmp(buf); 864 } 865 866 void outputComplementBmp(StringBuffer buf) { 867 cc.outputBmp(buf); 868 } 869 870 void addNonBmpRanges(List ranges) { 871 List tem = new Vector (); 872 cc.addNonBmpRanges(tem); 873 sortRangeList(tem); 874 int c = NONBMP_MIN; 875 for (int i = 0, len = tem.size(); i < len; i++) { 876 Range r = (Range)tem.get(i); 877 if (r.getMin() > c) 878 ranges.add(new Range(c, r.getMin() - 1)); 879 c = r.getMax() + 1; 880 } 881 if (c != NO
|