1 18 package org.apache.tools.ant.filters; 19 20 import java.io.IOException ; 21 import java.io.Reader ; 22 import org.apache.tools.ant.BuildException; 23 import org.apache.tools.ant.taskdefs.condition.Os; 24 import org.apache.tools.ant.types.EnumeratedAttribute; 25 26 72 public final class FixCrLfFilter extends BaseParamFilterReader implements ChainableReader { 73 private static final char CTRLZ = '\u001A'; 74 75 private int tabLength = 8; 76 77 private CrLf eol; 78 79 private AddAsisRemove ctrlz; 80 81 private AddAsisRemove tabs; 82 83 private boolean javafiles = false; 84 85 private boolean fixlast = true; 86 87 private boolean initialized = false; 88 89 94 public FixCrLfFilter() { 95 super(); 96 } 97 98 106 public FixCrLfFilter(final Reader in) throws IOException { 107 super(in); 108 } 109 110 { 113 tabs = AddAsisRemove.ASIS; 114 if (Os.isFamily("mac") && !Os.isFamily("unix")) { 115 ctrlz = AddAsisRemove.REMOVE; 116 setEol(CrLf.MAC); 117 } else if (Os.isFamily("dos")) { 118 ctrlz = AddAsisRemove.ASIS; 119 setEol(CrLf.DOS); 120 } else { 121 ctrlz = AddAsisRemove.REMOVE; 122 setEol(CrLf.UNIX); 123 } 124 } 125 126 136 public Reader chain(final Reader rdr) { 137 try { 138 FixCrLfFilter newFilter = new FixCrLfFilter(rdr); 139 140 newFilter.setJavafiles(getJavafiles()); 141 newFilter.setEol(getEol()); 142 newFilter.setTab(getTab()); 143 newFilter.setTablength(getTablength()); 144 newFilter.setEof(getEof()); 145 newFilter.setFixlast(getFixlast()); 146 newFilter.initInternalFilters(); 147 148 return newFilter; 149 } catch (IOException e) { 150 throw new BuildException(e); 151 } 152 } 153 154 164 public AddAsisRemove getEof() { 165 return ctrlz.newInstance(); 168 } 169 170 181 public CrLf getEol() { 182 return eol.newInstance(); 185 } 186 187 192 public boolean getFixlast() { 193 return fixlast; 194 } 195 196 207 public boolean getJavafiles() { 208 return javafiles; 209 } 210 211 222 public AddAsisRemove getTab() { 223 return tabs.newInstance(); 226 } 227 228 233 public int getTablength() { 234 return tabLength; 235 } 236 237 private static String calculateEolString(CrLf eol) { 238 if (eol == CrLf.ASIS) { 240 return System.getProperty("line.separator"); 241 } 242 if (eol == CrLf.CR || eol == CrLf.MAC) { 243 return "\r"; 244 } 245 if (eol == CrLf.CRLF || eol == CrLf.DOS) { 246 return "\r\n"; 247 } 248 return "\n"; 250 } 251 252 256 private void initInternalFilters() { 257 258 in = (ctrlz == AddAsisRemove.REMOVE) ? new RemoveEofFilter(in) : in; 261 262 in = new NormalizeEolFilter(in, calculateEolString(eol), getFixlast()); 266 267 if (tabs != AddAsisRemove.ASIS) { 268 if (getJavafiles()) { 271 in = new MaskJavaTabLiteralsFilter(in); 272 } 273 in = (tabs == AddAsisRemove.ADD) ? (Reader ) new AddTabFilter(in, getTablength()) 275 : (Reader ) new RemoveTabFilter(in, getTablength()); 276 } 277 in = (ctrlz == AddAsisRemove.ADD) ? new AddEofFilter(in) : in; 279 initialized = true; 280 } 281 282 292 public synchronized int read() throws IOException { 293 if (!initialized) { 294 initInternalFilters(); 295 } 296 return in.read(); 297 } 298 299 310 public void setEof(AddAsisRemove attr) { 311 ctrlz = attr.resolve(); 312 } 313 314 326 public void setEol(CrLf attr) { 327 eol = attr.resolve(); 328 } 329 330 336 public void setFixlast(boolean fixlast) { 337 this.fixlast = fixlast; 338 } 339 340 350 public void setJavafiles(boolean javafiles) { 351 this.javafiles = javafiles; 352 } 353 354 366 public void setTab(AddAsisRemove attr) { 367 tabs = attr.resolve(); 368 } 369 370 378 public void setTablength(int tabLength) throws IOException { 379 if (tabLength < 2 || tabLength > 80) { 380 throw new IOException ("tablength must be between 2 and 80"); 381 } 382 this.tabLength = tabLength; 383 } 384 385 395 private static class SimpleFilterReader extends Reader { 396 private Reader in; 397 398 private int[] preempt = new int[16]; 399 400 private int preemptIndex = 0; 401 402 public SimpleFilterReader(Reader in) { 403 this.in = in; 404 } 405 406 public void push(char c) { 407 push((int) c); 408 } 409 410 public void push(int c) { 411 try { 412 preempt[preemptIndex++] = c; 413 } catch (ArrayIndexOutOfBoundsException e) { 414 int[] p2 = new int[preempt.length * 2]; 415 System.arraycopy(preempt, 0, p2, 0, preempt.length); 416 preempt = p2; 417 push(c); 418 } 419 } 420 421 public void push(char[] cs, int start, int length) { 422 for (int i = start + length - 1; i >= start;) { 423 push(cs[i--]); 424 } 425 } 426 427 public void push(char[] cs) { 428 push(cs, 0, cs.length); 429 } 430 431 public void push(String s) { 432 push(s.toCharArray()); 433 } 434 435 439 public boolean editsBlocked() { 440 return in instanceof SimpleFilterReader && ((SimpleFilterReader) in).editsBlocked(); 441 } 442 443 public int read() throws java.io.IOException { 444 return preemptIndex > 0 ? preempt[--preemptIndex] : in.read(); 445 } 446 447 public void close() throws java.io.IOException { 448 in.close(); 449 } 450 451 public void reset() throws IOException { 452 in.reset(); 453 } 454 455 public boolean markSupported() { 456 return in.markSupported(); 457 } 458 459 public boolean ready() throws java.io.IOException { 460 return in.ready(); 461 } 462 463 public void mark(int i) throws java.io.IOException { 464 in.mark(i); 465 } 466 467 public long skip(long i) throws java.io.IOException { 468 return in.skip(i); 469 } 470 471 public int read(char[] buf) throws java.io.IOException { 472 return read(buf, 0, buf.length); 473 } 474 475 public int read(char[] buf, int start, int length) throws java.io.IOException { 476 int count = 0; 477 int c = 0; 478 479 while (length-- > 0 && (c = this.read()) != -1) { 480 buf[start++] = (char) c; 481 count++; 482 } 483 return (count == 0 && c == -1) ? -1 : count; 485 } 486 } 487 488 private static class MaskJavaTabLiteralsFilter extends SimpleFilterReader { 489 private boolean editsBlocked = false; 490 491 private static final int JAVA = 1; 492 493 private static final int IN_CHAR_CONST = 2; 494 495 private static final int IN_STR_CONST = 3; 496 497 private static final int IN_SINGLE_COMMENT = 4; 498 499 private static final int IN_MULTI_COMMENT = 5; 500 501 private static final int TRANS_TO_COMMENT = 6; 502 503 private static final int TRANS_FROM_MULTI = 8; 504 505 private int state; 506 507 public MaskJavaTabLiteralsFilter(Reader in) { 508 super(in); 509 state = JAVA; 510 } 511 512 public boolean editsBlocked() { 513 return editsBlocked || super.editsBlocked(); 514 } 515 516 public int read() throws IOException { 517 int thisChar = super.read(); 518 editsBlocked = (state == IN_CHAR_CONST || state == IN_STR_CONST); 520 521 switch (state) { 522 case JAVA: 523 switch (thisChar) { 525 case '\'': 526 state = IN_CHAR_CONST; 527 break; 528 case '"': 529 state = IN_STR_CONST; 530 break; 531 case '/': 532 state = TRANS_TO_COMMENT; 533 break; 534 default: 535 } 537 break; 538 case IN_CHAR_CONST: 539 switch (thisChar) { 540 case '\'': 541 state = JAVA; 542 break; 543 default: 544 } 546 break; 547 case IN_STR_CONST: 548 switch (thisChar) { 549 case '"': 550 state = JAVA; 551 break; 552 default: 553 } 555 break; 556 case IN_SINGLE_COMMENT: 557 switch (thisChar) { 559 case '\n': 560 case '\r': state = JAVA; 562 break; 563 default: 564 } 566 break; 567 case IN_MULTI_COMMENT: 568 switch (thisChar) { 570 case '*': 571 state = TRANS_FROM_MULTI; 572 break; 573 default: 574 } 576 break; 577 case TRANS_TO_COMMENT: 578 switch (thisChar) { 580 case '*': 581 state = IN_MULTI_COMMENT; 582 break; 583 case '/': 584 state = IN_SINGLE_COMMENT; 585 break; 586 case '\'': 587 state = IN_CHAR_CONST; 588 break; 589 case '"': 590 state = IN_STR_CONST; 591 break; 592 default: 593 state = JAVA; 594 } 595 break; 596 case TRANS_FROM_MULTI: 597 switch (thisChar) { 599 case '/': 600 state = JAVA; 601 break; 602 default: 603 } 605 break; 606 default: 607 } 609 return thisChar; 610 } 611 } 612 613 private static class NormalizeEolFilter extends SimpleFilterReader { 614 private boolean previousWasEOL; 615 616 private boolean fixLast; 617 618 private int normalizedEOL = 0; 619 620 private char[] eol = null; 621 622 public NormalizeEolFilter(Reader in, String eolString, boolean fixLast) { 623 super(in); 624 eol = eolString.toCharArray(); 625 this.fixLast = fixLast; 626 } 627 628 public int read() throws IOException { 629 int thisChar = super.read(); 630 631 if (normalizedEOL == 0) { 632 int numEOL = 0; 633 boolean atEnd = false; 634 switch (thisChar) { 635 case CTRLZ: 636 int c = super.read(); 637 if (c == -1) { 638 atEnd = true; 639 if (fixLast && !previousWasEOL) { 640 numEOL = 1; 641 push(thisChar); 642 } 643 } else { 644 push(c); 645 } 646 break; 647 case -1: 648 atEnd = true; 649 if (fixLast && !previousWasEOL) { 650 numEOL = 1; 651 } 652 break; 653 case '\n': 654 numEOL = 1; 656 break; 657 case '\r': 658 numEOL = 1; 659 int c1 = super.read(); 660 int c2 = super.read(); 661 662 if (c1 == '\r' && c2 == '\n') { 663 } else if (c1 == '\r') { 665 numEOL = 2; 668 push(c2); 669 } else if (c1 == '\n') { 670 push(c2); 672 } else { 673 push(c2); 675 push(c1); 676 } 677 default: 678 } 680 if (numEOL > 0) { 681 while (numEOL-- > 0) { 682 push(eol); 683 normalizedEOL += eol.length; 684 } 685 previousWasEOL = true; 686 thisChar = read(); 687 } else if (!atEnd) { 688 previousWasEOL = false; 689 } 690 } else { 691 normalizedEOL--; 692 } 693 return thisChar; 694 } 695 } 696 697 private static class AddEofFilter extends SimpleFilterReader { 698 private int lastChar = -1; 699 700 public AddEofFilter(Reader in) { 701 super(in); 702 } 703 704 public int read() throws IOException { 705 int thisChar = super.read(); 706 707 if (thisChar == -1) { 709 if (lastChar != CTRLZ) { 710 lastChar = CTRLZ; 711 return lastChar; 712 } 713 } else { 714 lastChar = thisChar; 715 } 716 return thisChar; 717 } 718 } 719 720 private static class RemoveEofFilter extends SimpleFilterReader { 721 private int lookAhead = -1; 722 723 public RemoveEofFilter(Reader in) { 724 super(in); 725 726 try { 727 lookAhead = in.read(); 728 } catch (IOException e) { 729 lookAhead = -1; 730 } 731 } 732 733 public int read() throws IOException { 734 int lookAhead2 = super.read(); 735 736 if (lookAhead2 == -1 && lookAhead == CTRLZ) { 738 return -1; 739 } 740 int i = lookAhead; 742 lookAhead = lookAhead2; 743 return i; 744 } 745 } 746 747 private static class AddTabFilter extends SimpleFilterReader { 748 private int columnNumber = 0; 749 750 private int tabLength = 0; 751 752 public AddTabFilter(Reader in, int tabLength) { 753 super(in); 754 this.tabLength = tabLength; 755 } 756 757 public int read() throws IOException { 758 int c = super.read(); 759 760 switch (c) { 761 case '\r': 762 case '\n': 763 columnNumber = 0; 764 break; 765 case ' ': 766 columnNumber++; 767 if (!editsBlocked()) { 768 int colNextTab = ((columnNumber + tabLength - 1) / tabLength) * tabLength; 769 int countSpaces = 1; 770 int numTabs = 0; 771 772 scanWhitespace: while ((c = super.read()) != -1) { 773 switch (c) { 774 case ' ': 775 if (++columnNumber == colNextTab) { 776 numTabs++; 777 countSpaces = 0; 778 colNextTab += tabLength; 779 } else { 780 countSpaces++; 781 } 782 break; 783 case '\t': 784 columnNumber = colNextTab; 785 numTabs++; 786 countSpaces = 0; 787 colNextTab += tabLength; 788 break; 789 default: 790 push(c); 791 break scanWhitespace; 792 } 793 } 794 while (countSpaces-- > 0) { 795 push(' '); 796 columnNumber--; 797 } 798 while (numTabs-- > 0) { 799 push('\t'); 800 columnNumber -= tabLength; 801 } 802 c = super.read(); 803 switch (c) { 804 case ' ': 805 columnNumber++; 806 break; 807 case '\t': 808 columnNumber += tabLength; 809 break; 810 default: 811 } 813 } 814 break; 815 case '\t': 816 columnNumber = ((columnNumber + tabLength - 1) / tabLength) * tabLength; 817 break; 818 default: 819 columnNumber++; 820 } 821 return c; 822 } 823 } 824 825 private static class RemoveTabFilter extends SimpleFilterReader { 826 private int columnNumber = 0; 827 828 private int tabLength = 0; 829 830 public RemoveTabFilter(Reader in, int tabLength) { 831 super(in); 832 833 this.tabLength = tabLength; 834 } 835 836 public int read() throws IOException { 837 int c = super.read(); 838 839 switch (c) { 840 case '\r': 841 case '\n': 842 columnNumber = 0; 843 break; 844 case '\t': 845 int width = tabLength - columnNumber % tabLength; 846 847 if (!editsBlocked()) { 848 for (; width > 1; width--) { 849 push(' '); 850 } 851 c = ' '; 852 } 853 columnNumber += width; 854 break; 855 default: 856 columnNumber++; 857 } 858 return c; 859 } 860 } 861 862 865 public static class AddAsisRemove extends EnumeratedAttribute { 866 private static final AddAsisRemove ASIS = newInstance("asis"); 867 868 private static final AddAsisRemove ADD = newInstance("add"); 869 870 private static final AddAsisRemove REMOVE = newInstance("remove"); 871 872 873 public String [] getValues() { 874 return new String [] {"add", "asis", "remove"}; 875 } 876 877 882 public boolean equals(Object other) { 883 return other instanceof AddAsisRemove 884 && getIndex() == ((AddAsisRemove) other).getIndex(); 885 } 886 887 891 public int hashCode() { 892 return getIndex(); 893 } 894 895 AddAsisRemove resolve() throws IllegalStateException { 896 if (this.equals(ASIS)) { 897 return ASIS; 898 } 899 if (this.equals(ADD)) { 900 return ADD; 901 } 902 if (this.equals(REMOVE)) { 903 return REMOVE; 904 } 905 throw new IllegalStateException ("No replacement for " + this); 906 } 907 908 private AddAsisRemove newInstance() { 910 return newInstance(getValue()); 911 } 912 913 918 public static AddAsisRemove newInstance(String value) { 919 AddAsisRemove a = new AddAsisRemove(); 920 a.setValue(value); 921 return a; 922 } 923 } 924 925 928 public static class CrLf extends EnumeratedAttribute { 929 private static final CrLf ASIS = newInstance("asis"); 930 931 private static final CrLf CR = newInstance("cr"); 932 933 private static final CrLf CRLF = newInstance("crlf"); 934 935 private static final CrLf DOS = newInstance("dos"); 936 937 private static final CrLf LF = newInstance("lf"); 938 939 private static final CrLf MAC = newInstance("mac"); 940 941 private static final CrLf UNIX = newInstance("unix"); 942 943 946 947 public String [] getValues() { 948 return new String [] {"asis", "cr", "lf", "crlf", "mac", "unix", "dos"}; 949 } 950 951 956 public boolean equals(Object other) { 957 return other instanceof CrLf && getIndex() == ((CrLf) other).getIndex(); 958 } 959 960 964 public int hashCode() { 965 return getIndex(); 966 } 967 968 CrLf resolve() { 969 if (this.equals(ASIS)) { 970 return ASIS; 971 } 972 if (this.equals(CR) || this.equals(MAC)) { 973 return CR; 974 } 975 if (this.equals(CRLF) || this.equals(DOS)) { 976 return CRLF; 977 } 978 if (this.equals(LF) || this.equals(UNIX)) { 979 return LF; 980 } 981 throw new IllegalStateException ("No replacement for " + this); 982 } 983 984 private CrLf newInstance() { 986 return newInstance(getValue()); 987 } 988 989 994 public static CrLf newInstance(String value) { 995 CrLf c = new CrLf(); 996 c.setValue(value); 997 return c; 998 } 999 } 1000} 1001 | Popular Tags |