Created
August 24, 2012 01:50
-
-
Save isapir/3444631 to your computer and use it in GitHub Desktop.
a class that can extends CFMLWriterWhiteSpace.java to allow for pre-formatted text in PRE tags and TEXTAREAs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.io.PrintStream; // TODO: this is for test purpose only; remove it when ridding of this.out | |
/** | |
* this class that can extends CFMLWriterWhiteSpace.java to allow for pre-formatted text in PRE tags and TEXTAREAs | |
*/ | |
public class CFMLWriterWhiteSpacePre extends javax.servlet.jsp.JspWriter { | |
/* snippet begin */ | |
public static final char CHAR_NL = '\n'; | |
public static final char CHAR_SP = ' '; | |
public static final char CHAR_LT = '<'; | |
private char lastChar = 0; | |
private int preDepth = 0; | |
private int txtDepth = 0; | |
private boolean doChangeWsToSpace = true; // can help fight XSS attacks with characters like Vertical Tab | |
private StringBuilder sb = new StringBuilder(); | |
/** | |
* prints the characters from the buffer and resets it | |
* | |
* TODO: make sure that printBuffer() is called at the end of the stream in case we have some characters there! (flush() ?) | |
*/ | |
private synchronized void printBuffer() { // TODO: not sure if synchronized is needed here? | |
int len = sb.length(); | |
char[] chars = new char[ len ]; | |
sb.getChars( 0, len, chars, 0 ); | |
sb.setLength( 0 ); | |
out.print( chars ); // TODO: change-to: super.write( chars, 0, chars.length ); | |
} | |
/** | |
* checks if a character is part of an open html tag or close html tag, and if so adds it to the buffer, otherwise returns false. | |
* | |
* @param c | |
* @return true if the char was added to the buffer, false otherwise | |
*/ | |
boolean addToBuffer( char c ) { | |
int len = sb.length(); | |
if ( len == 0 && c != CHAR_LT ) | |
return false; // buffer must starts with '<' | |
sb.append( c ); // if we reached this point then we will return true | |
if ( ++len > 5 ) { // increment len as it was sampled before we appended c | |
String substr = sb.substring( 1, 6 ); // we know that the 1st char is < so no need to test it | |
if ( substr.equalsIgnoreCase( "/pre>" ) ) { | |
if ( --preDepth < 0 ) preDepth = 0; // decrement and ensure non-negative | |
} else if ( substr.equalsIgnoreCase( "/text" ) ) { | |
if ( --txtDepth < 0 ) txtDepth = 0; // decrement and ensure non-negative | |
} | |
printBuffer(); | |
} else if ( len == 5 ) { | |
String substr = sb.substring( 1, 5 ); | |
if ( substr.equalsIgnoreCase( "pre>" ) ) { | |
preDepth++; | |
} else if ( substr.equalsIgnoreCase( "text" ) ) { | |
txtDepth++; | |
} | |
} | |
return true; | |
} | |
/** | |
* sends a character to output stream if it is not a consecutive white-space unless we're inside a PRE or TEXTAREA tag. | |
* | |
* @param c | |
* @throws IOException | |
*/ | |
@Override | |
public void print( char c ) throws IOException { | |
boolean isWS = Character.isWhitespace( c ); | |
if ( isWS && sb.length() > 0 ) | |
printBuffer(); // buffer should never contain WS so no need to call addToBuffer() | |
if ( isWS || !addToBuffer( c ) ) { | |
if ( preDepth + txtDepth == 0 ) { // we're not in PRE nor TEXTAREA; suppress whitespace | |
if ( isWS ) { // this char is WS | |
if ( lastChar == CHAR_NL ) // lastChar was NL; discard this WS char | |
return; | |
if ( c != CHAR_NL ) { // this WS char is not NL | |
if ( Character.isWhitespace( lastChar ) ) | |
return; // lastChar was WS but Not NL; discard this WS char | |
if ( doChangeWsToSpace ) | |
c = CHAR_SP; // this char is WS and not NL; change it to a regular space | |
} | |
} | |
} | |
lastChar = c; // remember c as lastChar and write it to output stream | |
out.print( c ); // TODO: change-to: call super.print( c ); | |
} | |
} | |
/* snippet end */ | |
/* test objects and methods below */ | |
PrintStream out = System.out; // for testing | |
public CFMLWriterWhiteSpacePre( int bufferSize, boolean autoFlush ) { | |
super( bufferSize, autoFlush ); | |
} | |
@Override | |
public void print(String string) throws IOException { | |
char[] chars = string.toCharArray(); | |
for ( char c : chars ) { | |
print( c ); | |
} | |
} | |
public static void main(String[] args) throws IOException { | |
CFMLWriterWhiteSpacePre w = new CFMLWriterWhiteSpacePre( 256, true ); | |
String[] strings = { | |
"this is a test without \t any \b tags." | |
, "this one is another\t\t\t\t\b \b \t string with no TAGs At All!" | |
, "this <b>one</b> HAS\t\t\t\t\b \b <h1>Some TAGs</h1> but nothing pre-formatted " | |
, "\n\n\n\n\t\t\t\n\n\n this String should be preceded by a single NL only. did it work? " | |
, "\t\t\t \n\n\n<PRE> S O M E\r\n\r\n\t\tP R E \r\n\r\n\t T E X T</PRE> and now outside the PRE..." | |
, " and this is the\r\n\tlast\t\t\t line." | |
}; | |
StringBuilder sb = new StringBuilder(); | |
for ( String s : strings ) { | |
if ( s.contains( "<PRE>" ) ) | |
System.out.println(""); | |
System.out.println( "[" + s + "]" ); | |
w.print( s ); | |
w.print( '\n' ); | |
sb.append(s).append("\r\n").append("\r\n").append("\r\n").append("\r\n").append("\r\n"); | |
} | |
String s = sb.toString(); | |
System.out.println( "[" + s + "]" ); | |
w.print( s ); | |
w.print( '\n' ); | |
} | |
/* JspWriter unsupported methods below */ | |
@Override | |
public void newLine() throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void print(boolean bln) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void print(int i) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void print(long l) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void print(float f) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void print(double d) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void print(char[] chars) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void print(Object o) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void println() throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void println(boolean bln) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void println(char c) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void println(int i) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void println(long l) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void println(float f) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void println(double d) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void println(char[] chars) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void println(String string) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void println(Object o) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void clear() throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void clearBuffer() throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void close() throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public int getRemaining() { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
@Override | |
public void write(char[] cbuf, int off, int len) throws IOException { | |
throw new UnsupportedOperationException("Not supported yet."); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment